From 30bc011ca90a3672a588fd8179c1eae4506d5a52 Mon Sep 17 00:00:00 2001
From: khartlage <khartlage>
Date: Sat, 9 Aug 2003 17:32:28 +0000
Subject: [PATCH 1/1] added a builder to parse files with eclipse's build mechanisms

---
 .../sourceforge/phpdt/core/BufferChangedEvent.java |  114 ++
 .../src/net/sourceforge/phpdt/core/IBuffer.java    |  263 ++++
 .../phpdt/core/IBufferChangedListener.java         |   30 +
 .../net/sourceforge/phpdt/core/IBufferFactory.java |   33 +
 .../net/sourceforge/phpdt/core/IJavaElement.java   |  304 +++++
 .../src/net/sourceforge/phpdt/core/IJavaModel.java |  256 ++++
 .../sourceforge/phpdt/core/IJavaModelStatus.java   |   84 ++
 .../phpdt/core/IJavaModelStatusConstants.java      |  283 ++++
 .../src/net/sourceforge/phpdt/core/IOpenable.java  |  168 +++
 .../src/net/sourceforge/phpdt/core/IParent.java    |   40 +
 .../sourceforge/phpdt/core/JavaModelException.java |  134 ++
 .../phpdt/core/util/ICacheEnumeration.java         |   39 +
 .../sourceforge/phpdt/core/util/ILRUCacheable.java |   28 +
 .../net/sourceforge/phpdt/core/util/LRUCache.java  |  499 ++++++++
 .../phpdt/core/util/ToStringSorter.java            |   75 ++
 .../sourceforge/phpdt/internal/core/Buffer.java    |  441 +++++++
 .../phpdt/internal/core/BufferCache.java           |   54 +
 .../phpdt/internal/core/BufferManager.java         |  107 ++
 .../phpdt/internal/core/JavaElement.java           |  654 ++++++++++
 .../phpdt/internal/core/JavaElementInfo.java       |  130 ++
 .../phpdt/internal/core/JavaModelStatus.java       |  451 +++++++
 .../phpdt/internal/core/LRUCacheEnumerator.java    |   69 +
 .../phpdt/internal/core/OverflowingLRUCache.java   |  426 ++++++
 .../net/sourceforge/phpdt/internal/core/Util.java  | 1352 ++++++++++++++++++++
 .../phpdt/internal/core/util/CharArrayBuffer.java  |  191 +++
 .../corext/phpdoc/PHPDocCommentReader.java         |   84 ++
 .../internal/corext/phpdoc/SingleCharReader.java   |   16 +-
 .../phpdt/internal/corext/util/Strings.java        |  260 ----
 .../phpdt/internal/ui/util/PHPElementVisitor.java  |    4 +-
 .../phpdt/internal/ui/util/PHPFileUtil.java        |   23 +
 .../phpeclipse/IPreferenceConstants.java           |    2 +-
 .../phpeclipse/PHPEclipseParserPreferencePage.java |   22 +-
 .../sourceforge/phpeclipse/PHPeclipsePlugin.java   |    9 +-
 .../phpeclipse/actions/PHPStartApacheAction.java   |   39 +-
 .../phpeclipse/builder/ParserBuilder.java          |  159 +++
 .../phpeclipse/builder/ParserVisitor.java          |   71 +
 .../phpeclipse/phpeditor/PHPEditor.java            |   46 +-
 .../phpeclipse/phpeditor/PHPParserAction.java      |   83 +-
 .../phpeclipse/resourcesview/PHPProject.java       |  343 +++---
 .../sourceforge/phpeclipse/views/PHPConsole.java   |   68 +-
 40 files changed, 6935 insertions(+), 519 deletions(-)
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/BufferChangedEvent.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBuffer.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferChangedListener.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferFactory.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaElement.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModel.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatus.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatusConstants.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IOpenable.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IParent.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/JavaModelException.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ICacheEnumeration.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ILRUCacheable.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/LRUCache.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ToStringSorter.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Buffer.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferCache.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferManager.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElement.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElementInfo.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaModelStatus.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/LRUCacheEnumerator.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/OverflowingLRUCache.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Util.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/CharArrayBuffer.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/PHPDocCommentReader.java
 delete mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/util/Strings.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPFileUtil.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserBuilder.java
 create mode 100644 net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserVisitor.java

diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/BufferChangedEvent.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/BufferChangedEvent.java
new file mode 100644
index 0000000..2b030b5
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/BufferChangedEvent.java
@@ -0,0 +1,114 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+import java.util.EventObject;
+
+/**
+ * A buffer changed event describes how a buffer has changed. These events are
+ * used in <code>IBufferChangedListener</code> notifications.
+ * <p>
+ * For text insertions, <code>getOffset</code> is the offset
+ * of the first inserted character, <code>getText</code> is the
+ * inserted text, and <code>getLength</code> is 0.
+ * </p>
+ * <p>
+ * For text removals, <code>getOffset</code> is the offset
+ * of the first removed character, <code>getText</code> is <code>null</code>,
+ * and <code>getLength</code> is the length of the text that was removed.
+ * </p>
+ * <p>
+ * For replacements (including <code>IBuffer.setContents</code>), 
+ * <code>getOffset</code> is the offset
+ * of the first replaced character, <code>getText</code> is the replacement
+ * text, and <code>getLength</code> is the length of the original text
+ * that was replaced.
+ * </p>
+ * <p>
+ * When a buffer is closed, <code>getOffset</code> is 0, <code>getLength</code>
+ * is 0, and <code>getText</code> is <code>null</code>.
+ * </p>
+ * <p>
+ * This class is not intended to be instantiated or subclassed by clients.
+ * Instances of this class are automatically created by the Java model.
+ * </p>
+ *
+ * @see IBuffer
+ */
+public class BufferChangedEvent extends EventObject {
+
+	/**
+	 * The length of text that has been modified in the buffer.
+	 */
+	private int length;
+
+	/**
+	 * The offset into the buffer where the modification took place.
+	 */
+	private int offset;
+
+	/**
+	 * The text that was modified.
+	 */
+	private String text;
+
+/**
+ * Creates a new buffer changed event indicating that the given buffer has changed.
+ * 
+ * @param buffer the given buffer
+ * @param offset the given offset
+ * @param length the given length
+ * @param text the given text
+ */
+public BufferChangedEvent(IBuffer buffer, int offset, int length, String text) {
+	super(buffer);
+	this.offset = offset;
+	this.length = length;
+	this.text = text;
+}
+/**
+ * Returns the buffer which has changed.
+ *
+ * @return the buffer affected by the change
+ */
+public IBuffer getBuffer() {
+	return (IBuffer) source;
+}
+/**
+ * Returns the length of text removed or replaced in the buffer, or
+ * 0 if text has been inserted into the buffer.
+ *
+ * @return the length of the original text fragment modified by the 
+ *   buffer change (<code> 0 </code> in case of insertion).
+ */
+public int getLength() {
+	return this.length;
+}
+/**
+ * Returns the index of the first character inserted, removed, or replaced
+ * in the buffer.
+ *
+ * @return the source offset of the textual manipulation in the buffer
+ */
+public int getOffset() {
+	return this.offset;
+}
+/**
+ * Returns the text that was inserted, the replacement text,
+ * or <code>null</code> if text has been removed.
+ *
+ * @return the text corresponding to the buffer change (<code> null </code>
+ *   in case of deletion).
+ */
+public String getText() {
+	return this.text;
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBuffer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBuffer.java
new file mode 100644
index 0000000..0a84671
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBuffer.java
@@ -0,0 +1,263 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * A buffer contains the text contents of a resource. It is not language-specific.
+ * The contents may be in the process of being edited, differing from the actual contents of the 
+ * underlying resource. A buffer has an owner, which is an <code>IOpenable</code>. 
+ * If a buffer does not have an underlying resource, saving the buffer has no effect. 
+ * Buffers can be read-only.
+ * <p>
+ * Note that java model operations that manipulate an <code>IBuffer</code> (for example, 
+ * <code>IType.createMethod(...)</code>) ensures that the same line delimiter 
+ * (either <code>"\n"</code> or <code>"\r"</code> or <code>"\r\n"</code>) is 
+ * used across the whole buffer. Thus these operations may change the line delimiter(s) 
+ * included in the string to be append, or replaced.
+ * However implementers of this interface should be aware that other clients of <code>IBuffer</code>
+ * might not do such transformations beforehand.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ */
+public interface IBuffer {
+	
+/**
+ * Adds the given listener for changes to this buffer.
+ * Has no effect if an identical listener is already registered or if the buffer
+ * is closed.
+ *
+ * @param listener the listener of buffer changes
+ */
+public void addBufferChangedListener(IBufferChangedListener listener);
+/**
+ * Appends the given character array to the contents of the buffer.
+ * This buffer will now have unsaved changes.
+ * Any client can append to the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ * <p>
+ * Has no effect if this buffer is read-only.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param text the given character array to append to contents of the buffer
+ */
+public void append(char[] text);
+/**
+ * Appends the given string to the contents of the buffer.
+ * This buffer will now have unsaved changes.
+ * Any client can append to the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ * <p>
+ * Has no effect if this buffer is read-only.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param text the <code>String</code> to append to the contents of the buffer
+ */
+public void append(String text);
+/**
+ * Closes the buffer. Any unsaved changes are lost. Reports a buffer changed event
+ * with a 0 offset and a 0 length. When this event is fired, the buffer should already
+ * be closed.
+ * <p>
+ * Further operations on the buffer are not allowed, except for close.  If an
+ * attempt is made to close an already closed buffer, the second attempt has no effect.
+ */
+public void close();
+/**
+ * Returns the character at the given position in this buffer.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param position a zero-based source offset in this buffer
+ * @return the character at the given position in this buffer
+ */
+public char getChar(int position);
+/**
+ * Returns the contents of this buffer as a character array, or <code>null</code> if
+ * the buffer has not been initialized.
+ * <p>
+ * Callers should make no assumption about whether the returned character array
+ * is or is not the genuine article or a copy. In other words, if the client
+ * wishes to change this array, they should make a copy. Likewise, if the
+ * client wishes to hang on to the array in its current state, they should
+ * make a copy.
+ * </p>
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @return the characters contained in this buffer
+ */
+public char[] getCharacters();
+/**
+ * Returns the contents of this buffer as a <code>String</code>. Like all strings,
+ * the result is an immutable value object., It can also answer <code>null</code> if
+ * the buffer has not been initialized.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @return the contents of this buffer as a <code>String</code>
+ */
+public String getContents();
+/**
+ * Returns number of characters stored in this buffer.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @return the number of characters in this buffer
+ */
+public int getLength();
+/**
+ * Returns the Java openable element owning of this buffer.
+ *
+ * @return the openable element owning this buffer
+ */
+public IOpenable getOwner();
+/**
+ * Returns the given range of text in this buffer.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param offset the  zero-based starting offset
+ * @param length the number of characters to retrieve
+ * @return the given range of text in this buffer
+ */
+public String getText(int offset, int length);
+/**
+ * Returns the underlying resource for which this buffer was opened,
+ * or <code>null</code> if this buffer was not opened on a resource.
+ *
+ * @return the underlying resource for this buffer, or <code>null</code>
+ *  if none.
+ */
+public IResource getUnderlyingResource();
+/**
+ * Returns whether this buffer has been modified since it
+ * was opened or since it was last saved.
+ * If a buffer does not have an underlying resource, this method always
+ * returns <code>true</code>.
+ *
+ * @return a <code>boolean</code> indicating presence of unsaved changes (in
+ *   the absence of any underlying resource, it will always return <code>true</code>).
+ */
+public boolean hasUnsavedChanges();
+/**
+ * Returns whether this buffer has been closed.
+ *
+ * @return a <code>boolean</code> indicating whether this buffer is closed.
+ */
+public boolean isClosed();
+/**
+ * Returns whether this buffer is read-only.
+ *
+ * @return a <code>boolean</code> indicating whether this buffer is read-only
+ */
+public boolean isReadOnly();
+/**
+ * Removes the given listener from this buffer.
+ * Has no affect if an identical listener is not registered or if the buffer is closed.
+ *
+ * @param listener the listener
+ */
+public void removeBufferChangedListener(IBufferChangedListener listener);
+/**
+ * Replaces the given range of characters in this buffer with the given text.
+ * <code>position</code> and <code>position + length</code> must be in the range [0, getLength()].
+ * <code>length</code> must not be negative.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param position the zero-based starting position of the affected text range in this buffer
+ * @param length the length of the affected text range in this buffer
+ * @param text the replacing text as a character array
+ */
+public void replace(int position, int length, char[] text);
+/**
+ * Replaces the given range of characters in this buffer with the given text.
+ * <code>position</code> and <code>position + length</code> must be in the range [0, getLength()].
+ * <code>length</code> must not be negative.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param position the zero-based starting position of the affected text range in this buffer
+ * @param length the length of the affected text range in this buffer
+ * @param text the replacing text as a <code>String</code>
+ */
+public void replace(int position, int length, String text);
+/**
+ * Saves the contents of this buffer to its underlying resource. If
+ * successful, this buffer will have no unsaved changes.
+ * The buffer is left open. Saving a buffer with no unsaved
+ * changes has no effect - the underlying resource is not changed.
+ * If the buffer does not have an underlying resource or is read-only, this
+ * has no effect.
+ * <p>
+ * The <code>force</code> parameter controls how this method deals with
+ * cases where the workbench is not completely in sync with the local file system.
+ * If <code>false</code> is specified, this method will only attempt
+ * to overwrite a corresponding file in the local file system provided
+ * it is in sync with the workbench. This option ensures there is no 
+ * unintended data loss; it is the recommended setting.
+ * However, if <code>true</code> is specified, an attempt will be made
+ * to write a corresponding file in the local file system, 
+ * overwriting any existing one if need be.
+ * In either case, if this method succeeds, the resource will be marked 
+ * as being local (even if it wasn't before).
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param progress the progress monitor to notify
+ * @param force a <code> boolean </code> flag indicating how to deal with resource
+ *   inconsistencies.
+ *
+ * @exception JavaModelException if an error occurs writing the buffer
+ *	to the underlying resource
+ *
+ * @see org.eclipse.core.resources.IFile#setContents(java.io.InputStream, boolean, boolean, org.eclipse.core.runtime.IProgressMonitor)
+ */
+public void save(IProgressMonitor progress, boolean force) throws JavaModelException;
+/**
+ * Sets the contents of this buffer to the given character array.
+ * This buffer will now have unsaved changes.
+ * Any client can set the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ * <p>
+ * Equivalent to <code>replace(0,getLength(),contents)</code>.
+ * </p>
+ * <p>
+ * Has no effect if this buffer is read-only.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param contents the new contents of this buffer as a character array
+ */
+public void setContents(char[] contents);
+/**
+ * Sets the contents of this buffer to the given <code>String</code>.
+ * This buffer will now have unsaved changes.
+ * Any client can set the contents of the buffer, not just the owner of the buffer.
+ * Reports a buffer changed event.
+ * <p>
+ * Equivalent to <code>replace(0,getLength(),contents)</code>.
+ * </p>
+ * <p>
+ * Has no effect if this buffer is read-only.
+ * <p>
+ * A <code>RuntimeException</code> might be thrown if the buffer is closed.
+ *
+ * @param contents the new contents of this buffer as a <code>String</code>
+ */
+public void setContents(String contents);
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferChangedListener.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferChangedListener.java
new file mode 100644
index 0000000..791fcc9
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferChangedListener.java
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+/**
+ * A listener, which gets notified when the contents of a specific buffer
+ * have changed, or when the buffer is closed.
+ * When a buffer is closed, the listener is notified <em>after</em> the buffer has been closed.
+ * A listener is not notified when a buffer is saved.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ */
+public interface IBufferChangedListener {
+
+	/** 
+	 * Notifies that the given event has occurred.
+	 *
+	 * @param event the change event
+	 */
+	public void bufferChanged(BufferChangedEvent event);
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferFactory.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferFactory.java
new file mode 100644
index 0000000..15b61e6
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IBufferFactory.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+/**
+ * A factory that creates <code>IBuffer</code>s for openables.
+ * <p>
+ * This interface may be implemented by clients.
+ * </p>
+ * @since 2.0
+ */
+public interface IBufferFactory {
+
+	/**
+	 * Creates a buffer for the given owner.
+	 * The new buffer will be initialized with the contents of the owner 
+	 * if and only if it was not already initialized by the factory (a buffer is uninitialized if 
+	 * its content is <code>null</code>).
+	 * 
+	 * @param owner the owner of the buffer
+	 * @see IBuffer
+	 */
+	IBuffer createBuffer(IOpenable owner);
+}
+
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaElement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaElement.java
new file mode 100644
index 0000000..a4160bb
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaElement.java
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+
+/**
+ * Common protocol for all elements provided by the Java model.
+ * Java model elements are exposed to clients as handles to the actual underlying element.
+ * The Java model may hand out any number of handles for each element. Handles
+ * that refer to the same element are guaranteed to be equal, but not necessarily identical.
+ * <p>
+ * Methods annotated as "handle-only" do not require underlying elements to exist. 
+ * Methods that require underlying elements to exist throw
+ * a <code>JavaModelException</code> when an underlying element is missing.
+ * <code>JavaModelException.isDoesNotExist</code> can be used to recognize
+ * this common special case.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IJavaElement extends IAdaptable {
+
+	/**
+	 * Constant representing a Java model (workspace level object).
+	 * A Java element with this type can be safely cast to <code>IJavaModel</code>.
+	 */
+	int JAVA_MODEL = 1;
+
+	/**
+	 * Constant representing a Java project.
+	 * A Java element with this type can be safely cast to <code>IJavaProject</code>.
+	 */
+	int JAVA_PROJECT = 2;
+
+	/**
+	 * Constant representing a package fragment root.
+	 * A Java element with this type can be safely cast to <code>IPackageFragmentRoot</code>.
+	 */
+	int PACKAGE_FRAGMENT_ROOT = 3;
+
+	/**
+	 * Constant representing a package fragment.
+	 * A Java element with this type can be safely cast to <code>IPackageFragment</code>.
+	 */
+	int PACKAGE_FRAGMENT = 4;
+
+	/**
+	 * Constant representing a Java compilation unit.
+	 * A Java element with this type can be safely cast to <code>ICompilationUnit</code>.
+	 */
+	int COMPILATION_UNIT = 5;
+
+	/**
+	 * Constant representing a class file.
+	 * A Java element with this type can be safely cast to <code>IClassFile</code>.
+	 */
+	int CLASS_FILE = 6;
+
+	/**
+	 * Constant representing a type (a class or interface).
+	 * A Java element with this type can be safely cast to <code>IType</code>.
+	 */
+	int TYPE = 7;
+
+	/**
+	 * Constant representing a field.
+	 * A Java element with this type can be safely cast to <code>IField</code>.
+	 */
+	int FIELD = 8;
+
+	/**
+	 * Constant representing a method or constructor.
+	 * A Java element with this type can be safely cast to <code>IMethod</code>.
+	 */
+	int METHOD = 9;
+
+	/**
+	 * Constant representing a stand-alone instance or class initializer.
+	 * A Java element with this type can be safely cast to <code>IInitializer</code>.
+	 */
+	int INITIALIZER = 10;
+
+	/**
+	 * Constant representing a package declaration within a compilation unit.
+	 * A Java element with this type can be safely cast to <code>IPackageDeclaration</code>.
+	 */
+	int PACKAGE_DECLARATION = 11;
+
+	/**
+	 * Constant representing all import declarations within a compilation unit.
+	 * A Java element with this type can be safely cast to <code>IImportContainer</code>.
+	 */
+	int IMPORT_CONTAINER = 12;
+
+	/**
+	 * Constant representing an import declaration within a compilation unit.
+	 * A Java element with this type can be safely cast to <code>IImportDeclaration</code>.
+	 */
+	int IMPORT_DECLARATION = 13;
+
+	/**
+	 * Returns whether this Java element exists in the model.
+	 * <p>
+	 * Java elements are handle objects that may or may not be backed by an
+	 * actual element. Java elements that are backed by an actual element are
+	 * said to "exist", and this method returns <code>true</code>. For Java
+	 * elements that are not working copies, it is always the case that if the
+	 * element exists, then its parent also exists (provided it has one) and
+	 * includes the element as one of its children. It is therefore possible
+	 * to navigated to any existing Java element from the root of the Java model
+	 * along a chain of existing Java elements. On the other hand, working
+	 * copies are said to exist until they are destroyed (with
+	 * <code>IWorkingCopy.destroy</code>). Unlike regular Java elements, a
+	 * working copy never shows up among the children of its parent element
+	 * (which may or may not exist).
+	 * </p>
+	 *
+	 * @return <code>true</code> if this element exists in the Java model, and
+	 * <code>false</code> if this element does not exist
+	 */
+	boolean exists();
+	
+	/**
+	 * Returns the first ancestor of this Java element that has the given type.
+	 * Returns <code>null</code> if no such an ancestor can be found.
+	 * This is a handle-only method.
+	 * 
+	 * @param ancestorType the given type
+	 * @return the first ancestor of this Java element that has the given type, null if no such an ancestor can be found
+	 * @since 2.0
+	 */
+	IJavaElement getAncestor(int ancestorType);
+
+	/**
+	 * Returns the resource that corresponds directly to this element,
+	 * or <code>null</code> if there is no resource that corresponds to
+	 * this element.
+	 * <p>
+	 * For example, the corresponding resource for an <code>ICompilationUnit</code>
+	 * is its underlying <code>IFile</code>. The corresponding resource for
+	 * an <code>IPackageFragment</code> that is not contained in an archive 
+	 * is its underlying <code>IFolder</code>. An <code>IPackageFragment</code>
+	 * contained in an archive has no corresponding resource. Similarly, there
+	 * are no corresponding resources for <code>IMethods</code>,
+	 * <code>IFields</code>, etc.
+	 * <p>
+	 *
+	 * @return the corresponding resource, or <code>null</code> if none
+	 * @exception JavaModelException if this element does not exist or if an
+	 *		exception occurs while accessing its corresponding resource
+	 */
+	IResource getCorrespondingResource() throws JavaModelException;
+
+	/**
+	 * Returns the name of this element. This is a handle-only method.
+	 *
+	 * @return the element name
+	 */
+	String getElementName();
+
+	/**
+	 * Returns this element's kind encoded as an integer.
+	 * This is a handle-only method.
+	 *
+	 * @return the kind of element; one of the constants declared in
+	 *   <code>IJavaElement</code>
+	 * @see IJavaElement
+	 */
+	int getElementType();
+
+	/**
+	 * Returns a string representation of this element handle. The format of
+	 * the string is not specified; however, the identifier is stable across
+	 * workspace sessions, and can be used to recreate this handle via the 
+	 * <code>JavaCore.create(String)</code> method.
+	 *
+	 * @return the string handle identifier
+	 * @see JavaCore#create(java.lang.String)
+	 */
+	String getHandleIdentifier();
+
+	/**
+	 * Returns the Java model.
+	 * This is a handle-only method.
+	 *
+	 * @return the Java model
+	 */
+	// IJavaModel getJavaModel();
+
+	/**
+	 * Returns the Java project this element is contained in,
+	 * or <code>null</code> if this element is not contained in any Java project
+	 * (for instance, the <code>IJavaModel</code> is not contained in any Java 
+	 * project).
+	 * This is a handle-only method.
+	 *
+	 * @return the containing Java project, or <code>null</code> if this element is
+	 *   not contained in a Java project
+	 */
+//	IJavaProject getJavaProject();
+
+	/**
+	 * Returns the first openable parent. If this element is openable, the element
+	 * itself is returned. Returns <code>null</code> if this element doesn't have
+	 * an openable parent.
+	 * This is a handle-only method.
+	 * 
+	 * @return the first openable parent or <code>null</code> if this element doesn't have
+	 * an openable parent.
+	 * @since 2.0
+	 */
+	IOpenable getOpenable();
+
+	/**
+	 * Returns the element directly containing this element,
+	 * or <code>null</code> if this element has no parent.
+	 * This is a handle-only method.
+	 *
+	 * @return the parent element, or <code>null</code> if this element has no parent
+	 */
+	IJavaElement getParent();
+
+	/**
+	 * Returns the path to the innermost resource enclosing this element. 
+	 * If this element is not included in an external archive, 
+	 * the path returned is the full, absolute path to the underlying resource, 
+	 * relative to the workbench. 
+	 * If this element is included in an external archive, 
+	 * the path returned is the absolute path to the archive in the file system.
+	 * This is a handle-only method.
+	 * 
+	 * @return the path to the innermost resource enclosing this element
+	 * @since 2.0
+	 */
+	IPath getPath();
+
+	/**
+	 * Returns the innermost resource enclosing this element. 
+	 * If this element is included in an archive and this archive is not external, 
+	 * this is the underlying resource corresponding to the archive. 
+	 * If this element is included in an external archive, <code>null</code>
+	 * is returned.
+	 * If this element is a working copy, <code>null</code> is returned.
+	 * This is a handle-only method.
+	 * 
+	 * @return the innermost resource enclosing this element, <code>null</code> if this 
+	 * element is a working copy or is included in an external archive
+	 * @since 2.0
+	 */
+	IResource getResource();
+
+	/**
+	 * Returns the smallest underlying resource that contains
+	 * this element, or <code>null</code> if this element is not contained
+	 * in a resource.
+	 *
+	 * @return the underlying resource, or <code>null</code> if none
+	 * @exception JavaModelException if this element does not exist or if an
+	 *		exception occurs while accessing its underlying resource
+	 */
+	IResource getUnderlyingResource() throws JavaModelException;
+
+	/**
+	 * Returns whether this Java element is read-only. An element is read-only
+	 * if its structure cannot be modified by the java model. 
+	 * <p>
+	 * Note this is different from IResource.isReadOnly(). For example, .jar
+	 * files are read-only as the java model doesn't know how to add/remove 
+	 * elements in this file, but the underlying IFile can be writable.
+	 * <p>
+	 * This is a handle-only method.
+	 *
+	 * @return <code>true</code> if this element is read-only
+	 */
+	boolean isReadOnly();
+
+	/**
+	 * Returns whether the structure of this element is known. For example, for a
+	 * compilation unit that could not be parsed, <code>false</code> is returned.
+	 * If the structure of an element is unknown, navigations will return reasonable
+	 * defaults. For example, <code>getChildren</code> will return an empty collection.
+	 * <p>
+	 * Note: This does not imply anything about consistency with the
+	 * underlying resource/buffer contents.
+	 * </p>
+	 *
+	 * @return <code>true</code> if the structure of this element is known
+	 * @exception JavaModelException if this element does not exist or if an
+	 *		exception occurs while accessing its corresponding resource
+	 */
+	boolean isStructureKnown() throws JavaModelException;
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModel.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModel.java
new file mode 100644
index 0000000..d745883
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModel.java
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Represent the root Java element corresponding to the workspace. 
+ * Since there is only one such root element, it is commonly referred to as
+ * <em>the</em> Java model element.
+ * The Java model element needs to be opened before it can be navigated or manipulated.
+ * The Java model element has no parent (it is the root of the Java element 
+ * hierarchy). Its children are <code>IJavaProject</code>s.
+ * <p>
+ * This interface provides methods for performing copy, move, rename, and
+ * delete operations on multiple Java elements.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients. An instance
+ * of one of these handles can be created via
+ * <code>JavaCore.create(workspace.getRoot())</code>.
+ * </p>
+ *
+ * @see JavaCore#create(org.eclipse.core.resources.IWorkspaceRoot)
+ */
+public interface IJavaModel extends IJavaElement, IOpenable, IParent {
+/**
+ * Returns whether this Java model contains an <code>IJavaElement</code> whose
+ * resource is the given resource or a non-Java resource which is the given resource.
+ * <p>
+ * Note: no existency check is performed on the argument resource. If it is not accessible 
+ * (see <code>IResource.isAccessible()</code>) yet but would be located in Java model 
+ * range, then it will return <code>true</code>.
+ * </p><p>
+ * If the resource is accessible, it can be reached by navigating the Java model down using the
+ * <code>getChildren()</code> and/or <code>getNonJavaResources()</code> methods.
+ * </p>
+ * @param resource the resource to check
+ * @return true if the resource is accessible through the Java model
+ * @since 2.1
+ */
+boolean contains(IResource resource);
+/**
+ * Copies the given elements to the specified container(s).
+ * If one container is specified, all elements are copied to that
+ * container. If more than one container is specified, the number of
+ * elements and containers must match, and each element is copied to
+ * its associated container.
+ * <p>
+ * Optionally, each copy can positioned before a sibling
+ * element. If <code>null</code> is specified for a given sibling, the copy
+ * is inserted as the last child of its associated container.
+ * </p>
+ * <p>
+ * Optionally, each copy can be renamed. If 
+ * <code>null</code> is specified for the new name, the copy
+ * is not renamed. 
+ * </p>
+ * <p>
+ * Optionally, any existing child in the destination container with
+ * the same name can be replaced by specifying <code>true</code> for
+ * force. Otherwise an exception is thrown in the event that a name
+ * collision occurs.
+ * </p>
+ *
+ * @param elements the elements to copy
+ * @param containers the container, or list of containers
+ * @param siblings the list of siblings element any of which may be
+ *   <code>null</code>; or <code>null</code>
+ * @param renamings the list of new names any of which may be
+ *   <code>null</code>; or <code>null</code>
+ * @param replace <code>true</code> if any existing child in a target container
+ *   with the target name should be replaced, and <code>false</code> to throw an
+ *   exception in the event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be copied. Reasons include:
+ * <ul>
+ * <li> There is no element to process (NO_ELEMENTS_TO_PROCESS). The given elements is null or empty</li>
+ * <li> A specified element, container, or sibling does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource</li>
+ * <li> A container is of an incompatible type (<code>INVALID_DESTINATION</code>)</li>
+ * <li> A sibling is not a child of it associated container (<code>INVALID_SIBLING</code>)</li>
+ * <li> A new name is invalid (<code>INVALID_NAME</code>)</li>
+ * <li> A child in its associated container already exists with the same
+ * 		name and <code>replace</code> has been specified as <code>false</code> (<code>NAME_COLLISION</code>)</li>
+ * <li> A container or element is read-only (<code>READ_ONLY</code>) </li>
+ * </ul>
+ */
+void copy(IJavaElement[] elements, IJavaElement[] containers, IJavaElement[] siblings, String[] renamings, boolean replace, IProgressMonitor monitor) throws JavaModelException;
+/**
+ * Deletes the given elements, forcing the operation if necessary and specified.
+ *
+ * @param elements the elements to delete
+ * @param force a flag controlling whether underlying resources that are not
+ *    in sync with the local file system will be tolerated
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be deleted. Reasons include:
+ * <ul>
+ * <li> There is no element to process (NO_ELEMENTS_TO_PROCESS). The given elements is null or empty</li>
+ * <li> A specified element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource</li>
+ * <li> An element is read-only (<code>READ_ONLY</code>) </li>
+ * </ul>
+ */
+void delete(IJavaElement[] elements, boolean force, IProgressMonitor monitor) throws JavaModelException;
+/**
+ * Returns the Java project with the given name. This is a handle-only method. 
+ * The project may or may not exist.
+ * 
+ * @return the Java project with the given name
+ */
+// IJavaProject getJavaProject(String name);
+/**
+ * Returns the Java projects in this Java model, or an empty array if there
+ * are none.
+ *
+ * @return the Java projects in this Java model, or an empty array if there
+ * are none
+ * @exception JavaModelException if this request fails.
+ */
+// IJavaProject[] getJavaProjects() throws JavaModelException;
+/**
+ * Returns an array of non-Java resources (that is, non-Java projects) in
+ * the workspace.
+ * <p>
+ * Non-Java projects include all projects that are closed (even if they have the
+ * Java nature).
+ * </p>
+ * 
+ * @return an array of non-Java projects contained in the workspace.
+ * @throws JavaModelException if this element does not exist or if an
+ *		exception occurs while accessing its corresponding resource
+ * @since 2.1
+ */
+Object[] getNonJavaResources() throws JavaModelException;
+/**
+ * Returns the workspace associated with this Java model.
+ * 
+ * @return the workspace associated with this Java model
+ */
+IWorkspace getWorkspace();
+/**
+ * Moves the given elements to the specified container(s).
+ * If one container is specified, all elements are moved to that
+ * container. If more than one container is specified, the number of
+ * elements and containers must match, and each element is moved to
+ * its associated container.
+ * <p>
+ * Optionally, each element can positioned before a sibling
+ * element. If <code>null</code> is specified for sibling, the element
+ * is inserted as the last child of its associated container.
+ * </p>
+ * <p>
+ * Optionally, each element can be renamed. If 
+ * <code>null</code> is specified for the new name, the element
+ * is not renamed. 
+ * </p>
+ * <p>
+ * Optionally, any existing child in the destination container with
+ * the same name can be replaced by specifying <code>true</code> for
+ * force. Otherwise an exception is thrown in the event that a name
+ * collision occurs.
+ * </p>
+ *
+ * @param elements the elements to move
+ * @param containers the container, or list of containers
+ * @param siblings the list of siblings element any of which may be
+ *   <code>null</code>; or <code>null</code>
+ * @param renamings the list of new names any of which may be
+ *   <code>null</code>; or <code>null</code>
+ * @param replace <code>true</code> if any existing child in a target container
+ *   with the target name should be replaced, and <code>false</code> to throw an
+ *   exception in the event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be moved. Reasons include:
+ * <ul>
+ * <li> There is no element to process (NO_ELEMENTS_TO_PROCESS). The given elements is null or empty</li>
+ * <li> A specified element, container, or sibling does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource</li>
+ * <li> A container is of an incompatible type (<code>INVALID_DESTINATION</code>)</li>
+ * <li> A sibling is not a child of it associated container (<code>INVALID_SIBLING</code>)</li>
+ * <li> A new name is invalid (<code>INVALID_NAME</code>)</li>
+ * <li> A child in its associated container already exists with the same
+ * 		name and <code>replace</code> has been specified as <code>false</code> (<code>NAME_COLLISION</code>)</li>
+ * <li> A container or element is read-only (<code>READ_ONLY</code>) </li>
+ * </ul>
+ *
+ * @exception IllegalArgumentException any element or container is <code>null</code>
+ */
+void move(IJavaElement[] elements, IJavaElement[] containers, IJavaElement[] siblings, String[] renamings, boolean replace, IProgressMonitor monitor) throws JavaModelException;
+
+/**
+ * Triggers an update of the JavaModel with respect to the referenced external archives.
+ * This operation will issue a JavaModel delta describing the discovered changes, in term
+ * of Java element package fragment roots added, removed or changed.
+ * Note that a collection of elements can be passed so as to narrow the set of archives
+ * to refresh (passing <code>null</code> along is equivalent to refreshing the entire mode). 
+ * The elements can be:
+ * <ul>
+ * <li> package fragment roots corresponding to external archives
+ * <li> Java projects, which referenced external archives will be refreshed
+ * <li> Java model, all referenced external archives will be refreshed.
+ * </ul>
+ * <p> In case an archive is used by multiple projects, the delta issued will account for
+ * all of them. This means that even if a project was not part of the elements scope, it
+ * may still be notified of changes if it is referencing a library comprised in the scope.
+ * <p>
+ * @param elementsScope - a collection of elements defining the scope of the refresh
+ * @param monitor - a progress monitor used to report progress
+ * @exception JavaModelException in one of the corresponding situation:
+ * <ul>
+ *    <li> an exception occurs while accessing project resources </li>
+ * </ul>
+ * 
+ * @see IJavaElementDelta
+ * @since 2.0
+ */
+void refreshExternalArchives(IJavaElement[] elementsScope, IProgressMonitor monitor) throws JavaModelException;
+
+/**
+ * Renames the given elements as specified.
+ * If one container is specified, all elements are renamed within that
+ * container. If more than one container is specified, the number of
+ * elements and containers must match, and each element is renamed within
+ * its associated container.
+ *
+ * @param elements the elements to rename
+ * @param destinations the container, or list of containers
+ * @param names the list of new names
+ * @param replace <code>true</code> if an existing child in a target container
+ *   with the target name should be replaced, and <code>false</code> to throw an
+ *   exception in the event of a name collision
+ * @param monitor a progress monitor
+ * @exception JavaModelException if an element could not be renamed. Reasons include:
+ * <ul>
+ * <li> There is no element to process (NO_ELEMENTS_TO_PROCESS). The given elements is null or empty</li>
+ * <li> A specified element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * <li> A <code>CoreException</code> occurred while updating an underlying resource
+ * <li> A new name is invalid (<code>INVALID_NAME</code>)
+ * <li> A child already exists with the same name and <code>replace</code> has been specified as <code>false</code> (<code>NAME_COLLISION</code>)
+ * <li> An element is read-only (<code>READ_ONLY</code>) 
+ * </ul>
+ */
+void rename(IJavaElement[] elements, IJavaElement[] destinations, String[] names, boolean replace, IProgressMonitor monitor) throws JavaModelException;
+
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatus.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatus.java
new file mode 100644
index 0000000..98c8565
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatus.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+
+/**
+ * Represents the outcome of an Java model operation. Status objects are
+ * used inside <code>JavaModelException</code> objects to indicate what went
+ * wrong.
+ * <p>
+ * Java model status object are distinguished by their plug-in id:
+ * <code>getPlugin</code> returns <code>"org.eclipse.jdt.core"</code>.
+ * <code>getCode</code> returns one of the status codes declared in
+ * <code>IJavaModelStatusConstants</code>.
+ * </p>
+ * <p>
+ * A Java model status may also carry additional information (that is, in 
+ * addition to the information defined in <code>IStatus</code>):
+ * <ul>
+ *   <li>elements - optional handles to Java elements associated with the failure</li>
+ *   <li>string - optional string associated with the failure</li>
+ * </ul>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ *
+ * @see org.eclipse.core.runtime.IStatus
+ * @see IJavaModelStatusConstants
+ */
+public interface IJavaModelStatus extends IStatus {
+/**
+ * Returns any Java elements associated with the failure (see specification
+ * of the status code), or an empty array if no elements are related to this
+ * particular status code.
+ *
+ * @return the list of Java element culprits
+ * @see IJavaModelStatusConstants
+ */
+public IJavaElement[] getElements();
+
+/**
+ * Returns the path associated with the failure (see specification
+ * of the status code), or <code>null</code> if the failure is not 
+ * one of <code>DEVICE_PATH</code>, <code>INVALID_PATH</code>, 
+ * <code>PATH_OUTSIDE_PROJECT</code>, or <code>RELATIVE_PATH</code>.
+ *
+ * @return the path that caused the failure, or <code>null</code> if none
+ * @see IJavaModelStatusConstants#DEVICE_PATH
+ * @see IJavaModelStatusConstants#INVALID_PATH
+ * @see IJavaModelStatusConstants#PATH_OUTSIDE_PROJECT
+ * @see IJavaModelStatusConstants#RELATIVE_PATH
+ */
+IPath getPath();
+/**
+ * Returns the string associated with the failure (see specification
+ * of the status code), or <code>null</code> if no string is related to this
+ * particular status code.
+ *
+ * @return the string culprit, or <code>null</code> if none
+ * @see IJavaModelStatusConstants
+ * @deprecated Use IStatus#getMessage instead
+ */
+String getString();
+/**
+ * Returns whether this status indicates that a Java model element does not exist.
+ * This convenience method is equivalent to
+ * <code>getCode() == IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST</code>.
+ *
+ * @return <code>true</code> if the status code indicates that a Java model
+ *   element does not exist
+ * @see IJavaModelStatusConstants#ELEMENT_DOES_NOT_EXIST
+ */
+boolean isDoesNotExist();
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatusConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatusConstants.java
new file mode 100644
index 0000000..aa108f9
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IJavaModelStatusConstants.java
@@ -0,0 +1,283 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+/**
+ * Status codes used with Java model status objects.
+ * <p>
+ * This interface declares constants only; it is not intended to be implemented
+ * or extended.
+ * </p>
+ *
+ * @see IJavaModelStatus
+ * @see org.eclipse.core.runtime.IStatus#getCode()
+ */
+public interface IJavaModelStatusConstants {
+
+	/**
+	 * Status constant indicating that a container path was resolved
+	 * to invalid entries (null or container).
+	 * 
+	 * @since 2.0
+	 */
+	public static final int INVALID_CP_CONTAINER_ENTRY = 962;
+
+	/**
+	 * Status constant indicating that a container path was not resolvable
+	 * indicating either the referred container is undefined, unbound.
+	 * 
+	 * @since 2.0
+	 */
+	public static final int CP_CONTAINER_PATH_UNBOUND = 963;
+
+	/**
+	 * Status constant indicating that a classpath entry was invalid
+	 */
+	public static final int INVALID_CLASSPATH = 964;
+
+	/**
+	 * Status constant indicating that a variable path was not resolvable
+	 * indicating either the referred variable is undefined, unbound or the resolved
+	 * variable path does not correspond to an existing file or folder.
+	 */
+	public static final int CP_VARIABLE_PATH_UNBOUND = 965;
+
+	/**
+	 * Status constant indicating a core exception occurred.
+	 * Use <code>getException</code> to retrieve a <code>CoreException</code>.
+	 */
+	public static final int CORE_EXCEPTION = 966;
+    
+	/**
+	 * Status constant indicating one or more of the elements
+	 * supplied are not of a valid type for the operation to
+	 * process. 
+	 * The element(s) can be retrieved using <code>getElements</code> on the status object.
+	 */
+	public static final int INVALID_ELEMENT_TYPES = 967;
+
+	/**
+	 * Status constant indicating that no elements were
+	 * provided to the operation for processing.
+	 */
+	public static final int NO_ELEMENTS_TO_PROCESS = 968;
+
+	/**
+	 * Status constant indicating that one or more elements
+	 * supplied do not exist. 
+	 * The element(s) can be retrieved using <code>getElements</code> on the status object.
+	 *
+	 * @see IJavaModelStatus#isDoesNotExist
+	 */
+	public static final int ELEMENT_DOES_NOT_EXIST = 969;
+
+	/**
+	 * Status constant indicating that a <code>null</code> path was
+	 * supplied to the operation.
+	 */
+	public static final int NULL_PATH = 970;
+    
+	/**
+	 * Status constant indicating that a path outside of the
+	 * project was supplied to the operation. The path can be retrieved using 
+	 * <code>getPath</code> on the status object.
+	 */
+	public static final int PATH_OUTSIDE_PROJECT = 971;
+    
+	/**
+	 * Status constant indicating that a relative path 
+	 * was supplied to the operation when an absolute path is
+	 * required. The path can be retrieved using <code>getPath</code> on the
+	 * status object.
+	 */
+	public static final int RELATIVE_PATH = 972;
+    
+	/**
+	 * Status constant indicating that a path specifying a device
+	 * was supplied to the operation when a path with no device is
+	 * required. The path can be retrieved using <code>getPath</code> on the
+	 * status object.
+	 */
+	public static final int DEVICE_PATH = 973;
+    
+	/**
+	 * Status constant indicating that a string
+	 * was supplied to the operation that was <code>null</code>.
+	 */
+	public static final int NULL_STRING = 974;
+    
+	/**
+	 * Status constant indicating that the operation encountered
+	 * a read-only element.
+	 * The element(s) can be retrieved using <code>getElements</code> on the status object.
+	 */
+	public static final int READ_ONLY = 976;
+    
+	/**
+	 * Status constant indicating that a naming collision would occur
+	 * if the operation proceeded.
+	 */
+	public static final int NAME_COLLISION = 977;
+    
+	/**
+	 * Status constant indicating that a destination provided for a copy/move/rename operation 
+	 * is invalid. 
+	 * The destination element can be retrieved using <code>getElements</code> on the status object.
+	 */
+	public static final int INVALID_DESTINATION = 978;
+    
+	/**
+	 * Status constant indicating that a path provided to an operation 
+	 * is invalid. The path can be retrieved using <code>getPath</code> on the
+	 * status object.
+	 */
+	public static final int INVALID_PATH = 979;
+    
+	/**
+	 * Status constant indicating the given source position is out of bounds.
+	 */
+	public static final int INDEX_OUT_OF_BOUNDS = 980;
+    
+	/**
+	 * Status constant indicating there is an update conflict
+	 * for a working copy. The compilation unit on which the
+	 * working copy is based has changed since the working copy
+	 * was created.
+	 */
+	public static final int UPDATE_CONFLICT = 981;
+
+	/**
+	 * Status constant indicating that <code>null</code> was specified
+	 * as a name argument.
+	 */
+	public static final int NULL_NAME = 982;
+
+	/**
+	 * Status constant indicating that a name provided is not syntactically correct.
+	 * The name can be retrieved from <code>getString</code>.
+	 */
+	public static final int INVALID_NAME = 983;
+
+	/**
+	 * Status constant indicating that the specified contents
+	 * are not valid.
+	 */
+	public static final int INVALID_CONTENTS = 984;
+
+	/**
+	 * Status constant indicating that an <code>java.io.IOException</code>
+	 * occurred. 
+	 */
+	public static final int IO_EXCEPTION = 985;
+
+	/**
+	 * Status constant indicating that a <code>DOMException</code>
+	 * occurred. 
+	 */
+	public static final int DOM_EXCEPTION = 986;
+
+	/**
+	 * Status constant indicating that a <code>TargetException</code>
+	 * occurred. 
+	 */
+	public static final int TARGET_EXCEPTION = 987;
+
+	/**
+	 * Status constant indicating that the Java builder
+	 * could not be initialized.
+	 */
+	public static final int BUILDER_INITIALIZATION_ERROR = 990;
+
+	/**
+	 * Status constant indicating that the Java builder's last built state
+	 * could not be serialized or deserialized.
+	 */
+	public static final int BUILDER_SERIALIZATION_ERROR = 991;
+
+	/**
+	 * Status constant indicating that an error was encountered while
+	 * trying to evaluate a code snippet, or other item.
+	 */
+	public static final int EVALUATION_ERROR = 992;
+
+	/**
+	 * Status constant indicating that a sibling specified is not valid.
+	 */
+	public static final int INVALID_SIBLING = 993;
+
+	/**
+	 * Status indicating that a Java element could not be created because
+	 * the underlying resource is invalid.
+	 * @see JavaCore
+	 */
+	 public static final int INVALID_RESOURCE = 995;
+
+	/**
+	 * Status indicating that a Java element could not be created because
+	 * the underlying resource is not of an appropriate type.
+	 * @see JavaCore
+	 */
+	 public static final int INVALID_RESOURCE_TYPE = 996;
+
+	/**
+	 * Status indicating that a Java element could not be created because
+	 * the project owning underlying resource does not have the Java nature.
+	 * @see JavaCore
+	 */
+	 public static final int INVALID_PROJECT = 997;
+
+	/**
+	 * Status indicating that the package declaration in a <code>ICompilationUnit</code>
+	 * does not correspond to the <code>IPackageFragment</code> it belongs to.
+	 * The <code>getString</code> method of the associated status object
+	 * gives the name of the package in which the <code>ICompilationUnit</code> is
+	 * declared.
+	 */
+	 public static final int INVALID_PACKAGE = 998;
+
+	/**
+	 * Status indicating that the corresponding resource has no local contents yet.
+	 * This might happen when attempting to use a resource before its contents
+	 * has been made locally available.
+	 */
+	 public static final int NO_LOCAL_CONTENTS = 999;
+	 
+	 /**
+	  * Status indicating that a .classpath file is ill-formed, and thus cannot
+	  * be read/written successfully.
+	  * @since 2.1
+	  */
+	 public static final int INVALID_CLASSPATH_FILE_FORMAT = 1000;
+
+	 /**
+	  * Status indicating that a project is involved in a build path cycle.
+	  * @since 2.1
+	  */
+	 public static final int CLASSPATH_CYCLE = 1001;
+	 
+	/**
+	 * Status constant indicating that an exclusion pattern got specified
+	 * on a classpath source entry, though it was explicitely disabled 
+	 * according to its project preference settings.
+	 * @see org.eclipse.jdt.core.IJavaProject#getOptions(boolean)
+	 * @since 2.1
+	 */
+	public static final int DISABLED_CP_EXCLUSION_PATTERNS = 1002;
+
+	/**
+	 * Status constant indicating that a specific output location got associated
+	 * with a source entry, though it was explicitely disabled according to its project
+	 * preference settings.
+	 * @see org.eclipse.jdt.core.IJavaProject#getOptions(boolean)
+	 * @since 2.1
+	 */
+	public static final int DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS = 1003;
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IOpenable.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IOpenable.java
new file mode 100644
index 0000000..474e764
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IOpenable.java
@@ -0,0 +1,168 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * Common protocol for Java elements that must be opened before they can be 
+ * navigated or modified. Opening a textual element (such as a compilation unit)
+ * involves opening a buffer on its contents.  While open, any changes to the buffer
+ * can be reflected in the element's structure; 
+ * see <code>isConsistent</code> and <code>makeConsistent(IProgressMonitor)</code>.
+ * <p>
+ * To reduce complexity in clients, elements are automatically opened
+ * by the Java model as element properties are accessed. The Java model maintains
+ * an LRU cache of open elements, and automatically closes elements as they
+ * are swapped out of the cache to make room for other elements. Elements with
+ * unsaved changes are never removed from the cache, and thus, if the client
+ * maintains many open elements with unsaved
+ * changes, the LRU cache can grow in size (in this case the cache is not
+ * bounded). However, as elements are saved, the cache will shrink back to its
+ * original bounded size.
+ * </p>
+ * <p>
+ * To open an element, all openable parent elements must be open.
+ * The Java model automatically opens parent elements, as it automatically opens elements.
+ * Opening an element may provide access to direct children and other descendants,
+ * but does not automatically open any descendents which are themselves <code>IOpenable</code>.
+ * For example, opening a compilation unit provides access to all its constituent elements,
+ * but opening a package fragment does not open all compilation units in the package fragment.
+ * </p>
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IOpenable {
+
+/**
+ * Closes this element and its buffer (if any).
+ * Closing an element which is not open has no effect.
+ *
+ * <p>Note: although <code>close</code> is exposed in the API, clients are
+ * not expected to open and close elements - the Java model does this automatically
+ * as elements are accessed.
+ *
+ * @exception JavaModelException if an error occurs closing this element
+ */
+public void close() throws JavaModelException;
+/**
+ * Returns the buffer opened for this element, or <code>null</code>
+ * if this element does not have a buffer.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *		exception occurs while accessing its corresponding resource.
+ * @return the buffer opened for this element, or <code>null</code>
+ * if this element does not have a buffer
+ */
+public IBuffer getBuffer() throws JavaModelException;
+/**
+ * Returns <code>true</code> if this element is open and:
+ * <ul>
+ * <li>its buffer has unsaved changes, or
+ * <li>one of its descendants has unsaved changes, or
+ * <li>a working copy has been created on one of this
+ * element's children and has not yet destroyed
+ * </ul>
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *		exception occurs while accessing its corresponding resource.
+ * @return <code>true</code> if this element is open and:
+ * <ul>
+ * <li>its buffer has unsaved changes, or
+ * <li>one of its descendants has unsaved changes, or
+ * <li>a working copy has been created on one of this
+ * element's children and has not yet destroyed
+ * </ul>
+ */
+boolean hasUnsavedChanges() throws JavaModelException;
+/**
+ * Returns whether the element is consistent with its underlying resource or buffer.
+ * The element is consistent when opened, and is consistent if the underlying resource
+ * or buffer has not been modified since it was last consistent.
+ *
+ * <p>NOTE: Child consistency is not considered. For example, a package fragment
+ * responds <code>true</code> when it knows about all of its
+ * compilation units present in its underlying folder. However, one or more of
+ * the compilation units could be inconsistent.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *		exception occurs while accessing its corresponding resource.
+ * @return true if the element is consistent with its underlying resource or buffer, false otherwise.
+ * @see IOpenable#makeConsistent
+ */
+boolean isConsistent() throws JavaModelException;
+/**
+ * Returns whether this openable is open. This is a handle-only method.
+ * @return true if this openable is open, false otherwise
+ */
+boolean isOpen();
+/**
+ * Makes this element consistent with its underlying resource or buffer 
+ * by updating the element's structure and properties as necessary.
+ *
+ * @param progress the given progress monitor
+ * @exception JavaModelException if the element is unable to access the contents
+ * 		of its underlying resource. Reasons include:
+ * <ul>
+ *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ * @see IOpenable#isConsistent
+ */
+void makeConsistent(IProgressMonitor progress) throws JavaModelException;
+/**
+ * Opens this element and all parent elements that are not already open.
+ * For compilation units, a buffer is opened on the contents of the underlying resource.
+ *
+ * <p>Note: although <code>open</code> is exposed in the API, clients are
+ * not expected to open and close elements - the Java model does this automatically
+ * as elements are accessed.
+ *
+ * @param progress the given progress monitor
+ * @exception JavaModelException if an error occurs accessing the contents
+ * 		of its underlying resource. Reasons include:
+ * <ul>
+ *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ * </ul>
+ */
+public void open(IProgressMonitor progress) throws JavaModelException;
+/**
+ * Saves any changes in this element's buffer to its underlying resource
+ * via a workspace resource operation. This has no effect if the element has no underlying
+ * buffer, or if there are no unsaved changed in the buffer.
+ * <p>
+ * The <code>force</code> parameter controls how this method deals with
+ * cases where the workbench is not completely in sync with the local file system.
+ * If <code>false</code> is specified, this method will only attempt
+ * to overwrite a corresponding file in the local file system provided
+ * it is in sync with the workbench. This option ensures there is no 
+ * unintended data loss; it is the recommended setting.
+ * However, if <code>true</code> is specified, an attempt will be made
+ * to write a corresponding file in the local file system, 
+ * overwriting any existing one if need be.
+ * In either case, if this method succeeds, the resource will be marked 
+ * as being local (even if it wasn't before).
+ * <p>
+ * As a result of this operation, the element is consistent with its underlying 
+ * resource or buffer. 
+ *
+ * @param progress the given progress monitor
+ * @param force it controls how this method deals with
+ * cases where the workbench is not completely in sync with the local file system
+ * @exception JavaModelException if an error occurs accessing the contents
+ * 		of its underlying resource. Reasons include:
+ * <ul>
+ *  <li>This Java element does not exist (ELEMENT_DOES_NOT_EXIST)</li>
+ *  <li>This Java element is read-only (READ_ONLY)</li>
+ * </ul>
+ */
+public void save(IProgressMonitor progress, boolean force) throws JavaModelException;
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IParent.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IParent.java
new file mode 100644
index 0000000..f1571c5
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/IParent.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+/**
+ * Common protocol for Java elements that contain other Java elements.
+ * <p>
+ * This interface is not intended to be implemented by clients.
+ * </p>
+ */
+public interface IParent {
+/**
+ * Returns the immediate children of this element.
+ * Unless otherwise specified by the implementing element,
+ * the children are in no particular order.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *      exception occurs while accessing its corresponding resource
+ * @return the immediate children of this element
+ */
+IJavaElement[] getChildren() throws JavaModelException;
+/**
+ * Returns whether this element has one or more immediate children.
+ * This is a convenience method, and may be more efficient than
+ * testing whether <code>getChildren</code> is an empty array.
+ *
+ * @exception JavaModelException if this element does not exist or if an
+ *      exception occurs while accessing its corresponding resource
+ * @return true if the immediate children of this element, false otherwise
+ */
+boolean hasChildren() throws JavaModelException;
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/JavaModelException.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/JavaModelException.java
new file mode 100644
index 0000000..a8d59f9
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/JavaModelException.java
@@ -0,0 +1,134 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core;
+
+import net.sourceforge.phpdt.internal.core.JavaModelStatus;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+
+//import org.eclipse.jdt.internal.core.JavaModelStatus;
+
+/**
+ * A checked exception representing a failure in the Java model.
+ * Java model exceptions contain a Java-specific status object describing the
+ * cause of the exception.
+ * <p>
+ * This class is not intended to be subclassed by clients. Instances of this
+ * class are automatically created by the Java model when problems arise, so
+ * there is generally no need for clients to create instances.
+ * </p>
+ *
+ * @see IJavaModelStatus
+ * @see IJavaModelStatusConstants
+ */
+public class JavaModelException extends CoreException {
+	CoreException nestedCoreException;
+/**
+ * Creates a Java model exception that wrappers the given <code>Throwable</code>.
+ * The exception contains a Java-specific status object with severity
+ * <code>IStatus.ERROR</code> and the given status code.
+ *
+ * @param exception the <code>Throwable</code>
+ * @param code one of the Java-specific status codes declared in
+ *   <code>IJavaModelStatusConstants</code>
+ * @see IJavaModelStatusConstants
+ * @see org.eclipse.core.runtime.IStatus#ERROR
+ */
+public JavaModelException(Throwable e, int code) {
+	this(new JavaModelStatus(code, e)); 
+}
+/**
+ * Creates a Java model exception for the given <code>CoreException</code>.
+ * Equivalent to 
+ * <code>JavaModelException(exception,IJavaModelStatusConstants.CORE_EXCEPTION</code>.
+ *
+ * @param exception the <code>CoreException</code>
+ */
+public JavaModelException(CoreException exception) {
+	super(exception.getStatus());
+	this.nestedCoreException = exception;
+}
+/**
+ * Creates a Java model exception for the given Java-specific status object.
+ *
+ * @param status the Java-specific status object
+ */
+public JavaModelException(IJavaModelStatus status) {
+	super(status);
+}
+/**
+ * Returns the underlying <code>Throwable</code> that caused the failure.
+ *
+ * @return the wrappered <code>Throwable</code>, or <code>null</code> if the
+ *   direct case of the failure was at the Java model layer
+ */
+public Throwable getException() {
+	if (this.nestedCoreException == null) {
+		return getStatus().getException();
+	} else {
+		return this.nestedCoreException;
+	}
+}
+/**
+ * Returns the Java model status object for this exception.
+ * Equivalent to <code>(IJavaModelStatus) getStatus()</code>.
+ *
+ * @return a status object
+ */
+public IJavaModelStatus getJavaModelStatus() {
+	IStatus status = this.getStatus();
+	if (status instanceof IJavaModelStatus) {
+		return (IJavaModelStatus)status;
+	} else {
+		// A regular IStatus is created only in the case of a CoreException.
+		// See bug 13492 Should handle JavaModelExceptions that contains CoreException more gracefully  
+		return new JavaModelStatus(this.nestedCoreException);
+	}
+}
+/**
+ * Returns whether this exception indicates that a Java model element does not
+ * exist. Such exceptions have a status with a code of
+ * <code>IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST</code>.
+ * This is a convenience method.
+ *
+ * @return <code>true</code> if this exception indicates that a Java model
+ *   element does not exist
+ * @see IJavaModelStatus#isDoesNotExist
+ * @see IJavaModelStatusConstants#ELEMENT_DOES_NOT_EXIST
+ */
+//public boolean isDoesNotExist() {
+//	IJavaModelStatus javaModelStatus = getJavaModelStatus();
+//	return javaModelStatus != null && javaModelStatus.isDoesNotExist();
+//}
+/**
+ * Returns a printable representation of this exception suitable for debugging
+ * purposes only.
+ */
+public String toString() {
+	StringBuffer buffer= new StringBuffer();
+	buffer.append("Java Model Exception: "); //$NON-NLS-1$
+	if (getException() != null) {
+		if (getException() instanceof CoreException) {
+			CoreException c= (CoreException)getException();
+			buffer.append("Core Exception [code "); //$NON-NLS-1$
+			buffer.append(c.getStatus().getCode());
+			buffer.append("] "); //$NON-NLS-1$
+			buffer.append(c.getStatus().getMessage());
+		} else {
+			buffer.append(getException().toString());
+		}
+	} else {
+		buffer.append(getStatus().toString());
+	}
+	return buffer.toString();
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ICacheEnumeration.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ICacheEnumeration.java
new file mode 100644
index 0000000..c1cbc30
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ICacheEnumeration.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core.util;
+
+import java.util.Enumeration;
+
+/**
+ * The <code>ICacheEnumeration</code> is used to iterate over both the keys 
+ * and values in an LRUCache.  The <code>getValue()</code> method returns the 
+ * value of the last key to be retrieved using <code>nextElement()</code>.  
+ * The <code>nextElement()</code> method must be called before the 
+ * <code>getValue()</code> method.
+ *
+ * <p>The iteration can be made efficient by making use of the fact that values in 
+ * the cache (instances of <code>LRUCacheEntry</code>), know their key.  For this reason,
+ * Hashtable lookups don't have to be made at each step of the iteration.
+ *
+ * <p>Modifications to the cache must not be performed while using the
+ * enumeration.  Doing so will lead to an illegal state.
+ *
+ * @see LRUCache
+ */
+public interface ICacheEnumeration extends Enumeration {
+	/**
+	 * Returns the value of the previously accessed key in the enumeration.
+	 * Must be called after a call to nextElement().
+	 *
+	 * @return Value of current cache entry
+	 */
+	public Object getValue();
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ILRUCacheable.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ILRUCacheable.java
new file mode 100644
index 0000000..d6da8b9
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ILRUCacheable.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core.util;
+
+/**
+ * Types implementing this interface can occupy a variable amount of space
+ * in an LRUCache.  Cached items that do not implement this interface are
+ * considered to occupy one unit of space.
+ *
+ * @see LRUCache
+ */
+public interface ILRUCacheable {
+	/**
+	 * Returns the space the receiver consumes in an LRU Cache.  The default space
+	 * value is 1.
+	 *
+	 * @return int Amount of cache space taken by the receiver
+	 */
+	public int getCacheFootprint();
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/LRUCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/LRUCache.java
new file mode 100644
index 0000000..5d715ce
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/LRUCache.java
@@ -0,0 +1,499 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core.util;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * The <code>LRUCache</code> is a hashtable that stores a finite number of elements.  
+ * When an attempt is made to add values to a full cache, the least recently used values
+ * in the cache are discarded to make room for the new values as necessary.
+ * 
+ * <p>The data structure is based on the LRU virtual memory paging scheme.
+ * 
+ * <p>Objects can take up a variable amount of cache space by implementing
+ * the <code>ILRUCacheable</code> interface.
+ *
+ * <p>This implementation is NOT thread-safe.  Synchronization wrappers would
+ * have to be added to ensure atomic insertions and deletions from the cache.
+ *
+ * @see org.eclipse.jdt.internal.core.util.ILRUCacheable
+ */
+public class LRUCache implements Cloneable {
+
+	/**
+	 * This type is used internally by the LRUCache to represent entries 
+	 * stored in the cache.
+	 * It is static because it does not require a pointer to the cache
+	 * which contains it.
+	 *
+	 * @see LRUCache
+	 */
+	protected static class LRUCacheEntry {
+		
+		/**
+		 * Hash table key
+		 */
+		public Object _fKey;
+		 
+		/**
+		 * Hash table value (an LRUCacheEntry object)
+		 */
+		public Object _fValue;		 
+
+		/**
+		 * Time value for queue sorting
+		 */
+		public int _fTimestamp;
+		
+		/**
+		 * Cache footprint of this entry
+		 */
+		public int _fSpace;
+		
+		/**
+		 * Previous entry in queue
+		 */
+		public LRUCacheEntry _fPrevious;
+			
+		/**
+		 * Next entry in queue
+		 */
+		public LRUCacheEntry _fNext;
+			
+		/**
+		 * Creates a new instance of the receiver with the provided values
+		 * for key, value, and space.
+		 */
+		public LRUCacheEntry (Object key, Object value, int space) {
+			_fKey = key;
+			_fValue = value;
+			_fSpace = space;
+		}
+
+		/**
+		 * Returns a String that represents the value of this object.
+		 */
+		public String toString() {
+
+			return "LRUCacheEntry [" + _fKey + "-->" + _fValue + "]"; //$NON-NLS-3$ //$NON-NLS-1$ //$NON-NLS-2$
+		}
+	}	
+
+	/**
+	 * Amount of cache space used so far
+	 */
+	protected int fCurrentSpace;
+	
+	/**
+	 * Maximum space allowed in cache
+	 */
+	protected int fSpaceLimit;
+	
+	/**
+	 * Counter for handing out sequential timestamps
+	 */
+	protected int	fTimestampCounter;
+	
+	/**
+	 * Hash table for fast random access to cache entries
+	 */
+	protected Hashtable fEntryTable;
+
+	/**
+	 * Start of queue (most recently used entry) 
+	 */	
+	protected LRUCacheEntry fEntryQueue;
+
+	/**
+	 * End of queue (least recently used entry)
+	 */	
+	protected LRUCacheEntry fEntryQueueTail;
+		
+	/**
+	 * Default amount of space in the cache
+	 */
+	protected static final int DEFAULT_SPACELIMIT = 100;
+	/**
+	 * Creates a new cache.  Size of cache is defined by 
+	 * <code>DEFAULT_SPACELIMIT</code>.
+	 */
+	public LRUCache() {
+		
+		this(DEFAULT_SPACELIMIT);
+	}
+	/**
+	 * Creates a new cache.
+	 * @param size Size of Cache
+	 */
+	public LRUCache(int size) {
+		
+		fTimestampCounter = fCurrentSpace = 0;
+		fEntryQueue = fEntryQueueTail = null;
+		fEntryTable = new Hashtable(size);
+		fSpaceLimit = size;
+	}
+	/**
+	 * Returns a new cache containing the same contents.
+	 *
+	 * @return New copy of object.
+	 */
+	public Object clone() {
+		
+		LRUCache newCache = newInstance(fSpaceLimit);
+		LRUCacheEntry qEntry;
+		
+		/* Preserve order of entries by copying from oldest to newest */
+		qEntry = this.fEntryQueueTail;
+		while (qEntry != null) {
+			newCache.privateAdd (qEntry._fKey, qEntry._fValue, qEntry._fSpace);
+			qEntry = qEntry._fPrevious;
+		}
+		return newCache;
+	}
+	/**
+	 * Flushes all entries from the cache.
+	 */
+	public void flush() {
+
+		fCurrentSpace = 0;
+		LRUCacheEntry entry = fEntryQueueTail; // Remember last entry
+		fEntryTable = new Hashtable();  // Clear it out
+		fEntryQueue = fEntryQueueTail = null;  
+		while (entry != null) {  // send deletion notifications in LRU order
+			privateNotifyDeletionFromCache(entry);
+			entry = entry._fPrevious;
+		}
+	}
+	/**
+	 * Flushes the given entry from the cache.  Does nothing if entry does not
+	 * exist in cache.
+	 *
+	 * @param key Key of object to flush
+	 */
+	public void flush (Object key) {
+		
+		LRUCacheEntry entry;
+		
+		entry = (LRUCacheEntry) fEntryTable.get(key);
+
+		/* If entry does not exist, return */
+		if (entry == null) return;
+
+		this.privateRemoveEntry (entry, false);
+	}
+	/**
+	 * Answers the value in the cache at the given key.
+	 * If the value is not in the cache, returns null
+	 *
+	 * @param key Hash table key of object to retrieve
+	 * @return Retreived object, or null if object does not exist
+	 */
+	public Object get(Object key) {
+		
+		LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+		if (entry == null) {
+			return null;
+		}
+		
+		this.updateTimestamp (entry);
+		return entry._fValue;
+	}
+	/**
+	 * Returns the amount of space that is current used in the cache.
+	 */
+	public int getCurrentSpace() {
+		return fCurrentSpace;
+	}
+	/**
+	 * Returns the maximum amount of space available in the cache.
+	 */
+	public int getSpaceLimit() {
+		return fSpaceLimit;
+	}
+	/**
+	 * Returns an Enumeration of the keys currently in the cache.
+	 */
+	public Enumeration keys() {
+		
+		return fEntryTable.keys();
+	}
+	/**
+	 * Returns an enumeration that iterates over all the keys and values 
+	 * currently in the cache.
+	 */
+	public ICacheEnumeration keysAndValues() {
+		return new ICacheEnumeration() {
+		
+			Enumeration fValues = fEntryTable.elements();
+			LRUCacheEntry fEntry;
+			
+			public boolean hasMoreElements() {
+				return fValues.hasMoreElements();
+			}
+			
+			public Object nextElement() {
+				fEntry = (LRUCacheEntry) fValues.nextElement();
+				return fEntry._fKey;
+			}
+			
+			public Object getValue() {
+				if (fEntry == null) {
+					throw new java.util.NoSuchElementException();
+				}
+				return fEntry._fValue;
+			}
+		};
+	}
+	/**
+	 * Ensures there is the specified amount of free space in the receiver,
+	 * by removing old entries if necessary.  Returns true if the requested space was
+	 * made available, false otherwise.
+	 *
+	 * @param space Amount of space to free up
+	 */
+	protected boolean makeSpace (int space) {
+		
+		int limit;
+		
+		limit = this.getSpaceLimit();
+		
+		/* if space is already available */
+		if (fCurrentSpace + space <= limit) {
+			return true;
+		}
+		
+		/* if entry is too big for cache */
+		if (space > limit) {
+			return false;
+		}
+		
+		/* Free up space by removing oldest entries */
+		while (fCurrentSpace + space > limit && fEntryQueueTail != null) {
+			this.privateRemoveEntry (fEntryQueueTail, false);
+		}
+		return true;
+	}
+	/**
+	 * Returns a new LRUCache instance
+	 */
+	protected LRUCache newInstance(int size) {
+		return new LRUCache(size);
+	}
+	/**
+	 * Adds an entry for the given key/value/space.
+	 */
+	protected void privateAdd (Object key, Object value, int space) {
+		
+		LRUCacheEntry entry;
+		
+		entry = new LRUCacheEntry(key, value, space);
+		this.privateAddEntry (entry, false);
+	}
+	/**
+	 * Adds the given entry from the receiver.
+	 * @param shuffle Indicates whether we are just shuffling the queue 
+	 * (in which case, the entry table is not modified).
+	 */
+	protected void privateAddEntry (LRUCacheEntry entry, boolean shuffle) {
+		
+		if (!shuffle) {
+			fEntryTable.put (entry._fKey, entry);
+			fCurrentSpace += entry._fSpace;
+		}
+		
+		entry._fTimestamp = fTimestampCounter++;
+		entry._fNext = this.fEntryQueue;
+		entry._fPrevious = null;
+		
+		if (fEntryQueue == null) {
+			/* this is the first and last entry */
+			fEntryQueueTail = entry;
+		} else {
+			fEntryQueue._fPrevious = entry;
+		}
+		
+		fEntryQueue = entry;
+	}
+	/**
+	 * An entry has been removed from the cache, for example because it has 
+	 * fallen off the bottom of the LRU queue.  
+	 * Subclasses could over-ride this to implement a persistent cache below the LRU cache.
+	 */
+	protected void privateNotifyDeletionFromCache(LRUCacheEntry entry) {
+		// Default is NOP.
+	}
+	/**
+	 * Removes the entry from the entry queue.  
+	 * @param shuffle indicates whether we are just shuffling the queue 
+	 * (in which case, the entry table is not modified).
+	 */
+	protected void privateRemoveEntry (LRUCacheEntry entry, boolean shuffle) {
+		
+		LRUCacheEntry previous, next;
+		
+		previous = entry._fPrevious;
+		next = entry._fNext;
+		
+		if (!shuffle) {
+			fEntryTable.remove(entry._fKey);
+			fCurrentSpace -= entry._fSpace;
+			privateNotifyDeletionFromCache(entry);
+		}
+
+		/* if this was the first entry */
+		if (previous == null) {
+			fEntryQueue = next;
+		} else {
+			previous._fNext = next;
+		}
+
+		/* if this was the last entry */
+		if (next == null) {
+			fEntryQueueTail = previous;
+		} else {
+			next._fPrevious = previous;
+		}
+	}
+	/**
+	 * Sets the value in the cache at the given key. Returns the value.
+	 *
+	 * @param key Key of object to add.
+	 * @param value Value of object to add.
+	 * @return added value.
+	 */
+	public Object put(Object key, Object value) {
+		
+		int newSpace, oldSpace, newTotal;
+		LRUCacheEntry entry;
+		
+		/* Check whether there's an entry in the cache */
+		newSpace = spaceFor (key, value);
+		entry = (LRUCacheEntry) fEntryTable.get (key);
+		
+		if (entry != null) {
+			
+			/**
+			 * Replace the entry in the cache if it would not overflow
+			 * the cache.  Otherwise flush the entry and re-add it so as 
+			 * to keep cache within budget
+			 */
+			oldSpace = entry._fSpace;
+			newTotal = getCurrentSpace() - oldSpace + newSpace;
+			if (newTotal <= getSpaceLimit()) {
+				updateTimestamp (entry);
+				entry._fValue = value;
+				entry._fSpace = newSpace;
+				this.fCurrentSpace = newTotal;
+				return value;
+			} else {
+				privateRemoveEntry (entry, false);
+			}
+		}
+		if (makeSpace(newSpace)) {
+			privateAdd (key, value, newSpace);
+		}
+		return value;
+	}
+	/**
+	 * Removes and returns the value in the cache for the given key.
+	 * If the key is not in the cache, returns null.
+	 *
+	 * @param key Key of object to remove from cache.
+	 * @return Value removed from cache.
+	 */
+	public Object removeKey (Object key) {
+		
+		LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+		if (entry == null) {
+			return null;
+		}
+		Object value = entry._fValue;
+		this.privateRemoveEntry (entry, false);
+		return value;
+	}
+	/**
+	 * Sets the maximum amount of space that the cache can store
+	 *
+	 * @param limit Number of units of cache space
+	 */
+	public void setSpaceLimit(int limit) {
+		if (limit < fSpaceLimit) {
+			makeSpace(fSpaceLimit - limit);
+		}
+		fSpaceLimit = limit;
+	}
+	/**
+	 * Returns the space taken by the given key and value.
+	 */
+	protected int spaceFor (Object key, Object value) {
+		
+		if (value instanceof ILRUCacheable) {
+			return ((ILRUCacheable) value).getCacheFootprint();
+		} else {
+			return 1;
+		}
+	}
+/**
+ * Returns a String that represents the value of this object.  This method
+ * is for debugging purposes only.
+ */
+public String toString() {
+	return 
+		"LRUCache " + (fCurrentSpace * 100.0 / fSpaceLimit) + "% full\n" + //$NON-NLS-1$ //$NON-NLS-2$
+		this.toStringContents();
+}
+/**
+ * Returns a String that represents the contents of this object.  This method
+ * is for debugging purposes only.
+ */
+protected String toStringContents() {
+	StringBuffer result = new StringBuffer();
+	int length = fEntryTable.size();
+	Object[] unsortedKeys = new Object[length];
+	String[] unsortedToStrings = new String[length];
+	Enumeration e = this.keys();
+	for (int i = 0; i < length; i++) {
+		Object key = e.nextElement();
+		unsortedKeys[i] = key;
+//		unsortedToStrings[i] = 
+//			(key instanceof org.eclipse.jdt.internal.core.JavaElement) ?
+//				((org.eclipse.jdt.internal.core.JavaElement)key).getElementName() :
+//				key.toString();
+		unsortedToStrings[i] = key.toString();
+	}
+	ToStringSorter sorter = new ToStringSorter();
+	sorter.sort(unsortedKeys, unsortedToStrings);
+	for (int i = 0; i < length; i++) {
+		String toString = sorter.sortedStrings[i];
+		Object value = this.get(sorter.sortedObjects[i]);
+		result.append(toString);		
+		result.append(" -> "); //$NON-NLS-1$
+		result.append(value);
+		result.append("\n"); //$NON-NLS-1$
+	}
+	return result.toString();
+}
+	/**
+	 * Updates the timestamp for the given entry, ensuring that the queue is 
+	 * kept in correct order.  The entry must exist
+	 */
+	protected void updateTimestamp (LRUCacheEntry entry) {
+		
+		entry._fTimestamp = fTimestampCounter++;
+		if (fEntryQueue != entry) {
+			this.privateRemoveEntry (entry, true);
+			this.privateAddEntry (entry, true);
+		}
+		return;
+	}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ToStringSorter.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ToStringSorter.java
new file mode 100644
index 0000000..ce4ed4f
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/core/util/ToStringSorter.java
@@ -0,0 +1,75 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.core.util;
+
+/**
+ * The SortOperation takes a collection of objects and returns
+ * a sorted collection of these objects. The sorting of these
+ * objects is based on their toString(). They are sorted in
+ * alphabetical order.
+ */
+public class ToStringSorter {
+	Object[] sortedObjects;
+	String[] sortedStrings;
+/**
+ *  Returns true if stringTwo is 'greater than' stringOne
+ *  This is the 'ordering' method of the sort operation.
+ */
+public boolean compare(String stringOne, String stringTwo) {
+	return stringOne.compareTo(stringTwo) < 0;
+}
+/**
+ *  Sort the objects in sorted collection and return that collection.
+ */
+private void quickSort(int left, int right) {
+	int originalLeft = left;
+	int originalRight = right;
+	int midIndex =  (left + right) / 2;
+	String midToString = this.sortedStrings[midIndex];
+	
+	do {
+		while (compare(this.sortedStrings[left], midToString))
+			left++;
+		while (compare(midToString, this.sortedStrings[right]))
+			right--;
+		if (left <= right) {
+			Object tmp = this.sortedObjects[left];
+			this.sortedObjects[left] = this.sortedObjects[right];
+			this.sortedObjects[right] = tmp;
+			String tmpToString = this.sortedStrings[left];
+			this.sortedStrings[left] = this.sortedStrings[right];
+			this.sortedStrings[right] = tmpToString;
+			left++;
+			right--;
+		}
+	} while (left <= right);
+	
+	if (originalLeft < right)
+		quickSort(originalLeft, right);
+	if (left < originalRight)
+		quickSort(left, originalRight);
+}
+/**
+ *  Return a new sorted collection from this unsorted collection.
+ *  Sort using quick sort.
+ */
+public void sort(Object[] unSortedObjects, String[] unsortedStrings) {
+	int size = unSortedObjects.length;
+	this.sortedObjects = new Object[size];
+	this.sortedStrings = new String[size];
+	
+	//copy the array so can return a new sorted collection  
+	System.arraycopy(unSortedObjects, 0, this.sortedObjects, 0, size);
+	System.arraycopy(unsortedStrings, 0, this.sortedStrings, 0, size);
+	if (size > 1)
+		quickSort(0, size - 1);
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Buffer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Buffer.java
new file mode 100644
index 0000000..c26691d
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Buffer.java
@@ -0,0 +1,441 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import net.sourceforge.phpdt.core.BufferChangedEvent;
+import net.sourceforge.phpdt.core.IBuffer;
+import net.sourceforge.phpdt.core.IBufferChangedListener;
+import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
+import net.sourceforge.phpdt.core.IOpenable;
+import net.sourceforge.phpdt.core.JavaModelException;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * @see IBuffer
+ */
+public class Buffer implements IBuffer {
+	protected IFile file;
+	protected int flags;
+	protected char[] contents;
+	protected ArrayList changeListeners;
+	protected IOpenable owner;
+	protected int gapStart= -1;
+	protected int gapEnd= -1;
+
+	protected Object lock= new Object();
+
+	protected static final int F_HAS_UNSAVED_CHANGES= 1;
+	protected static final int F_IS_READ_ONLY= 2;
+	protected static final int F_IS_CLOSED= 4;
+
+/**
+ * Creates a new buffer on an underlying resource.
+ */
+protected Buffer(IFile file, IOpenable owner, boolean readOnly) {
+	this.file = file;
+	this.owner = owner;
+	if (file == null) {
+		setReadOnly(readOnly);
+	}
+}
+/**
+ * @see IBuffer
+ */
+public void addBufferChangedListener(IBufferChangedListener listener) {
+	if (this.changeListeners == null) {
+		this.changeListeners = new ArrayList(5);
+	}
+	if (!this.changeListeners.contains(listener)) {
+		this.changeListeners.add(listener);
+	}
+}
+/**
+ * Append the <code>text</code> to the actual content, the gap is moved
+ * to the end of the <code>text</code>.
+ */
+public void append(char[] text) {
+	if (!isReadOnly()) {
+		if (text == null || text.length == 0) {
+			return;
+		}
+		int length = getLength();
+		moveAndResizeGap(length, text.length);
+		System.arraycopy(text, 0, this.contents, length, text.length);
+		this.gapStart += text.length;
+		this.flags |= F_HAS_UNSAVED_CHANGES;
+		notifyChanged(new BufferChangedEvent(this, length, 0, new String(text)));
+	}
+}
+/**
+ * Append the <code>text</code> to the actual content, the gap is moved
+ * to the end of the <code>text</code>.
+ */
+public void append(String text) {
+	if (text == null) {
+		return;
+	}
+	this.append(text.toCharArray());
+}
+/**
+ * @see IBuffer
+ */
+public void close() throws IllegalArgumentException {
+	BufferChangedEvent event = null;
+	synchronized (this.lock) {
+		if (isClosed())
+			return;
+		event = new BufferChangedEvent(this, 0, 0, null);
+		this.contents = null;
+		this.flags |= F_IS_CLOSED;
+	}
+	notifyChanged(event); // notify outside of synchronized block
+	this.changeListeners = null;
+}
+/**
+ * @see IBuffer
+ */
+public char getChar(int position) {
+	synchronized (this.lock) {
+		if (position < this.gapStart) {
+			return this.contents[position];
+		}
+		int gapLength = this.gapEnd - this.gapStart;
+		return this.contents[position + gapLength];
+	}
+}
+/**
+ * @see IBuffer
+ */
+public char[] getCharacters() {
+	if (this.contents == null) return null;
+	synchronized (this.lock) {
+		if (this.gapStart < 0) {
+			return this.contents;
+		}
+		int length = this.contents.length;
+		char[] newContents = new char[length - this.gapEnd + this.gapStart];
+		System.arraycopy(this.contents, 0, newContents, 0, this.gapStart);
+		System.arraycopy(this.contents, this.gapEnd, newContents, this.gapStart, length - this.gapEnd);
+		return newContents;
+	}
+}
+/**
+ * @see IBuffer
+ */
+public String getContents() {
+	char[] chars = this.getCharacters();
+	if (chars == null) return null;
+	return new String(chars);
+}
+/**
+ * @see IBuffer
+ */
+public int getLength() {
+	synchronized (this.lock) {
+		int length = this.gapEnd - this.gapStart;
+		return (this.contents.length - length);
+	}
+}
+/**
+ * @see IBuffer
+ */
+public IOpenable getOwner() {
+	return this.owner;
+}
+/**
+ * @see IBuffer
+ */
+public String getText(int offset, int length) {
+	if (this.contents == null)
+		return ""; //$NON-NLS-1$
+	synchronized (this.lock) {
+		if (offset + length < this.gapStart)
+			return new String(this.contents, offset, length);
+		if (this.gapStart < offset) {
+			int gapLength = this.gapEnd - this.gapStart;
+			return new String(this.contents, offset + gapLength, length);
+		}
+		StringBuffer buf = new StringBuffer();
+		buf.append(this.contents, offset, this.gapStart - offset);
+		buf.append(this.contents, this.gapEnd, offset + length - this.gapStart);
+		return buf.toString();
+	}
+}
+/**
+ * @see IBuffer
+ */
+public IResource getUnderlyingResource() {
+	return this.file;
+}
+/**
+ * @see IBuffer
+ */
+public boolean hasUnsavedChanges() {
+	return (this.flags & F_HAS_UNSAVED_CHANGES) != 0;
+}
+/**
+ * @see IBuffer
+ */
+public boolean isClosed() {
+	return (this.flags & F_IS_CLOSED) != 0;
+}
+/**
+ * @see IBuffer
+ */
+public boolean isReadOnly() {
+	if (this.file == null) {
+		return (this.flags & F_IS_READ_ONLY) != 0;
+	} else {
+		return this.file.isReadOnly();
+	}
+}
+/**
+ * Moves the gap to location and adjust its size to the
+ * anticipated change size. The size represents the expected 
+ * range of the gap that will be filled after the gap has been moved.
+ * Thus the gap is resized to actual size + the specified size and
+ * moved to the given position.
+ */
+protected void moveAndResizeGap(int position, int size) {
+	char[] content = null;
+	int oldSize = this.gapEnd - this.gapStart;
+	if (size < 0) {
+		if (oldSize > 0) {
+			content = new char[this.contents.length - oldSize];
+			System.arraycopy(this.contents, 0, content, 0, this.gapStart);
+			System.arraycopy(this.contents, this.gapEnd, content, this.gapStart, content.length - this.gapStart);
+			this.contents = content;
+		}
+		this.gapStart = this.gapEnd = position;
+		return;
+	}
+	content = new char[this.contents.length + (size - oldSize)];
+	int newGapStart = position;
+	int newGapEnd = newGapStart + size;
+	if (oldSize == 0) {
+		System.arraycopy(this.contents, 0, content, 0, newGapStart);
+		System.arraycopy(this.contents, newGapStart, content, newGapEnd, content.length - newGapEnd);
+	} else
+		if (newGapStart < this.gapStart) {
+			int delta = this.gapStart - newGapStart;
+			System.arraycopy(this.contents, 0, content, 0, newGapStart);
+			System.arraycopy(this.contents, newGapStart, content, newGapEnd, delta);
+			System.arraycopy(this.contents, this.gapEnd, content, newGapEnd + delta, this.contents.length - this.gapEnd);
+		} else {
+			int delta = newGapStart - this.gapStart;
+			System.arraycopy(this.contents, 0, content, 0, this.gapStart);
+			System.arraycopy(this.contents, this.gapEnd, content, this.gapStart, delta);
+			System.arraycopy(this.contents, this.gapEnd + delta, content, newGapEnd, content.length - newGapEnd);
+		}
+	this.contents = content;
+	this.gapStart = newGapStart;
+	this.gapEnd = newGapEnd;
+}
+/**
+ * Notify the listeners that this buffer has changed.
+ * To avoid deadlock, this should not be called in a synchronized block.
+ */
+protected void notifyChanged(final BufferChangedEvent event) {
+	if (this.changeListeners != null) {
+		for (int i = 0, size = this.changeListeners.size(); i < size; ++i) {
+			final IBufferChangedListener listener = (IBufferChangedListener) this.changeListeners.get(i);
+			Platform.run(new ISafeRunnable() {
+				public void handleException(Throwable exception) {
+					Util.log(exception, "Exception occurred in listener of buffer change notification"); //$NON-NLS-1$
+				}
+				public void run() throws Exception {
+					listener.bufferChanged(event);
+				}
+			});
+			
+		}
+	}
+}
+/**
+ * @see IBuffer
+ */
+public void removeBufferChangedListener(IBufferChangedListener listener) {
+	if (this.changeListeners != null) {
+		this.changeListeners.remove(listener);
+		if (this.changeListeners.size() == 0) {
+			this.changeListeners = null;
+		}
+	}
+}
+/**
+ * Replaces <code>length</code> characters starting from <code>position</code> with <code>text<code>.
+ * After that operation, the gap is placed at the end of the 
+ * inserted <code>text</code>.
+ */
+public void replace(int position, int length, char[] text) {
+	if (!isReadOnly()) {
+		int textLength = text == null ? 0 : text.length;
+		synchronized (this.lock) {
+			// move gap
+			moveAndResizeGap(position + length, textLength - length);
+
+			// overwrite
+			int min = Math.min(textLength, length);
+			if (min > 0) {
+				System.arraycopy(text, 0, this.contents, position, min);
+			}
+			if (length > textLength) {
+				// enlarge the gap
+				this.gapStart -= length - textLength;
+			} else if (textLength > length) {
+				// shrink gap
+				this.gapStart += textLength - length;
+				System.arraycopy(text, 0, this.contents, position, textLength);
+			}
+		}
+		this.flags |= F_HAS_UNSAVED_CHANGES;
+		String string = null;
+		if (textLength > 0) {
+			string = new String(text);
+		}
+		notifyChanged(new BufferChangedEvent(this, position, length, string));
+	}
+}
+/**
+ * Replaces <code>length</code> characters starting from <code>position</code> with <code>text<code>.
+ * After that operation, the gap is placed at the end of the 
+ * inserted <code>text</code>.
+ */
+public void replace(int position, int length, String text) {
+	this.replace(position, length, text == null ? null : text.toCharArray());
+}
+/**
+ * @see IBuffer
+ */
+public void save(IProgressMonitor progress, boolean force) throws JavaModelException {
+
+	// determine if saving is required 
+	if (isReadOnly() || this.file == null) {
+		return;
+	}
+	synchronized (this.lock) {
+		if (!hasUnsavedChanges())
+			return;
+			
+		// use a platform operation to update the resource contents
+		try {
+//			String encoding = ((IJavaElement)this.owner).getJavaProject().getOption(PHPCore.CORE_ENCODING, true);
+			String encoding = null;
+			String contents = this.getContents();
+			if (contents == null) return;
+			byte[] bytes = encoding == null 
+				? contents.getBytes() 
+				: contents.getBytes(encoding);
+			ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
+
+			this.file.setContents(
+				stream, 
+				force ? IResource.FORCE | IResource.KEEP_HISTORY : IResource.KEEP_HISTORY, 
+				null);
+		} catch (IOException e) {
+			throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+		} catch (CoreException e) {
+			throw new JavaModelException(e);
+		}
+
+		// the resource no longer has unsaved changes
+		this.flags &= ~ (F_HAS_UNSAVED_CHANGES);
+	}
+}
+/**
+ * @see IBuffer
+ */
+public void setContents(char[] newContents) {
+	// allow special case for first initialization 
+	// after creation by buffer factory
+	if (this.contents == null) {
+		this.contents = newContents;
+		this.flags &= ~ (F_HAS_UNSAVED_CHANGES);
+		return;
+	}
+	
+	if (!isReadOnly()) {
+		String string = null;
+		if (newContents != null) {
+			string = new String(newContents);
+		}
+		BufferChangedEvent event = new BufferChangedEvent(this, 0, this.getLength(), string);
+		synchronized (this.lock) {
+			this.contents = newContents;
+			this.flags |= F_HAS_UNSAVED_CHANGES;
+			this.gapStart = -1;
+			this.gapEnd = -1;
+		}
+		notifyChanged(event);
+	}
+}
+/**
+ * @see IBuffer
+ */
+public void setContents(String newContents) {
+	this.setContents(newContents.toCharArray());
+}
+/**
+ * Sets this <code>Buffer</code> to be read only.
+ */
+protected void setReadOnly(boolean readOnly) {
+	if (readOnly) {
+		this.flags |= F_IS_READ_ONLY;
+	} else {
+		this.flags &= ~(F_IS_READ_ONLY);
+	}
+}
+public String toString() {
+	StringBuffer buffer = new StringBuffer();
+//	buffer.append("Owner: " + ((JavaElement)this.owner).toStringWithAncestors()); //$NON-NLS-1$
+	buffer.append("Owner: " + (this.owner).toString()); //$NON-NLS-1$
+	buffer.append("\nHas unsaved changes: " + this.hasUnsavedChanges()); //$NON-NLS-1$
+	buffer.append("\nIs readonly: " + this.isReadOnly()); //$NON-NLS-1$
+	buffer.append("\nIs closed: " + this.isClosed()); //$NON-NLS-1$
+	buffer.append("\nContents:\n"); //$NON-NLS-1$
+	char[] contents = this.getCharacters();
+	if (contents == null) {
+		buffer.append("<null>"); //$NON-NLS-1$
+	} else {
+		int length = contents.length;
+		for (int i = 0; i < length; i++) {
+			char car = contents[i];
+			switch (car) {
+				case '\n': 
+					buffer.append("\\n\n"); //$NON-NLS-1$
+					break;
+				case '\r':
+					if (i < length-1 && this.contents[i+1] == '\n') {
+						buffer.append("\\r\\n\n"); //$NON-NLS-1$
+						i++;
+					} else {
+						buffer.append("\\r\n"); //$NON-NLS-1$
+					}
+					break;
+				default:
+					buffer.append(car);
+					break;
+			}
+		}
+	}
+	return buffer.toString();
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferCache.java
new file mode 100644
index 0000000..62ad8f0
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferCache.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core;
+
+import net.sourceforge.phpdt.core.IBuffer;
+import net.sourceforge.phpdt.core.util.LRUCache;
+
+/**
+ * An LRU cache of <code>IBuffers</code>.
+ */
+public class BufferCache extends OverflowingLRUCache {
+/**
+ * Constructs a new buffer cache of the given size.
+ */
+public BufferCache(int size) {
+	super(size);
+}
+/**
+ * Constructs a new buffer cache of the given size.
+ */
+public BufferCache(int size, int overflow) {
+	super(size, overflow);
+}
+/**
+ * Returns true if the buffer is successfully closed and
+ * removed from the cache, otherwise false.
+ *
+ * <p>NOTE: this triggers an external removal of this buffer
+ * by closing the buffer.
+ */
+protected boolean close(LRUCacheEntry entry) {
+	IBuffer buffer= (IBuffer) entry._fValue;
+	if (buffer.hasUnsavedChanges()) {
+		return false;
+	} else {
+		buffer.close();
+		return true;
+	}
+}
+	/**
+	 * Returns a new instance of the reciever.
+	 */
+	protected LRUCache newInstance(int size, int overflow) {
+		return new BufferCache(size, overflow);
+	}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferManager.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferManager.java
new file mode 100644
index 0000000..511d041
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/BufferManager.java
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core;
+
+import java.util.Enumeration;
+
+import net.sourceforge.phpdt.core.IBuffer;
+import net.sourceforge.phpdt.core.IBufferFactory;
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IOpenable;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+
+
+/**
+ * The buffer manager manages the set of open buffers.
+ * It implements an LRU cache of buffers.
+ */
+public class BufferManager implements IBufferFactory {
+
+	protected static BufferManager DEFAULT_BUFFER_MANAGER;
+
+	/**
+	 * LRU cache of buffers. The key and value for an entry
+	 * in the table is the identical buffer.
+	 */
+	protected OverflowingLRUCache openBuffers = new BufferCache(60);
+
+/**
+ * Creates a new buffer manager.
+ */
+public BufferManager() {
+}
+/**
+ * Adds a buffer to the table of open buffers.
+ */
+protected void addBuffer(IBuffer buffer) {
+	openBuffers.put(buffer.getOwner(), buffer);
+}
+/**
+ * @see IBufferFactory#createBuffer(IOpenable)
+ */
+public IBuffer createBuffer(IOpenable owner) {
+	IJavaElement element = (IJavaElement)owner;
+	IResource resource = element.getResource();
+	return 
+		new Buffer(
+			resource instanceof IFile ? (IFile)resource : null, 
+			owner, 
+			element.isReadOnly());
+}
+
+/**
+ * Returns the open buffer associated with the given owner,
+ * or <code>null</code> if the owner does not have an open
+ * buffer associated with it.
+ */
+public IBuffer getBuffer(IOpenable owner) {
+	return (IBuffer)openBuffers.get(owner);
+}
+/**
+ * Returns the default buffer manager.
+ */
+public synchronized static BufferManager getDefaultBufferManager() {
+	if (DEFAULT_BUFFER_MANAGER == null) {
+		DEFAULT_BUFFER_MANAGER = new BufferManager();
+	}
+	return DEFAULT_BUFFER_MANAGER;
+}
+/**
+ * Returns the default buffer factory.
+ */
+public IBufferFactory getDefaultBufferFactory() {
+	return this;
+}
+/**
+ * Returns an enumeration of all open buffers.
+ * <p> 
+ * The <code>Enumeration</code> answered is thread safe.
+ *
+ * @see OverflowingLRUCache
+ * @return Enumeration of IBuffer
+ */
+public Enumeration getOpenBuffers() {
+	synchronized (openBuffers) {
+		openBuffers.shrink();
+		return openBuffers.elements();
+	}
+}
+
+
+/**
+ * Removes a buffer from the table of open buffers.
+ */
+protected void removeBuffer(IBuffer buffer) {
+	openBuffers.remove(buffer.getOwner());
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElement.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElement.java
new file mode 100644
index 0000000..590b8db
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElement.java
@@ -0,0 +1,654 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core;
+
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IJavaModel;
+import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
+import net.sourceforge.phpdt.core.IOpenable;
+import net.sourceforge.phpdt.core.IParent;
+import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.internal.corext.Assert;
+
+import org.eclipse.core.resources.IResourceStatus;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.core.runtime.PlatformObject;
+
+/**
+ * Root of Java element handle hierarchy.
+ *
+ * @see IJavaElement
+ */
+public abstract class JavaElement extends PlatformObject implements IJavaElement {
+
+	public static final char JEM_JAVAPROJECT= '=';
+	public static final char JEM_PACKAGEFRAGMENTROOT= Path.SEPARATOR;
+	public static final char JEM_PACKAGEFRAGMENT= '<';
+	public static final char JEM_FIELD= '^';
+	public static final char JEM_METHOD= '~';
+	public static final char JEM_INITIALIZER= '|';
+	public static final char JEM_COMPILATIONUNIT= '{';
+	public static final char JEM_CLASSFILE= '(';
+	public static final char JEM_TYPE= '[';
+	public static final char JEM_PACKAGEDECLARATION= '%';
+	public static final char JEM_IMPORTDECLARATION= '#';
+
+	/**
+	 * A count to uniquely identify this element in the case
+	 * that a duplicate named element exists. For example, if
+	 * there are two fields in a compilation unit with the
+	 * same name, the occurrence count is used to distinguish
+	 * them.  The occurrence count starts at 1 (thus the first 
+	 * occurrence is occurrence 1, not occurrence 0).
+	 */
+	protected int fOccurrenceCount = 1;
+
+
+	/**
+	 * This element's type - one of the constants defined
+	 * in IJavaLanguageElementTypes.
+	 */
+	protected int fLEType = 0;
+
+	/**
+	 * This element's parent, or <code>null</code> if this
+	 * element does not have a parent.
+	 */
+	protected IJavaElement fParent;
+
+	/**
+	 * This element's name, or an empty <code>String</code> if this
+	 * element does not have a name.
+	 */
+	protected String fName;
+
+	protected static final Object NO_INFO = new Object();
+	
+	/**
+	 * Constructs a handle for a java element of the specified type, with
+	 * the given parent element and name.
+	 *
+	 * @param type - one of the constants defined in IJavaLanguageElement
+	 *
+	 * @exception IllegalArgumentException if the type is not one of the valid
+	 *		Java element type constants
+	 *
+	 */
+	protected JavaElement(int type, IJavaElement parent, String name) throws IllegalArgumentException {
+		if (type < JAVA_MODEL || type > IMPORT_DECLARATION) {
+			throw new IllegalArgumentException(Util.bind("element.invalidType")); //$NON-NLS-1$
+		}
+		fLEType= type;
+		fParent= parent;
+		fName= name;
+	}
+	/**
+	 * @see IOpenable
+	 */
+//	public void close() throws JavaModelException {
+//		Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
+//		if (info != null) {
+//			boolean wasVerbose = false;
+//			try {
+//				if (JavaModelManager.VERBOSE) {
+//					System.out.println("CLOSING Element ("+ Thread.currentThread()+"): " + this.toStringWithAncestors());  //$NON-NLS-1$//$NON-NLS-2$
+//					wasVerbose = true;
+//					JavaModelManager.VERBOSE = false;
+//				}
+//				if (this instanceof IParent) {
+//					IJavaElement[] children = ((JavaElementInfo) info).getChildren();
+//					for (int i = 0, size = children.length; i < size; ++i) {
+//						JavaElement child = (JavaElement) children[i];
+//						child.close();
+//					}
+//				}
+//				closing(info);
+//				JavaModelManager.getJavaModelManager().removeInfo(this);
+//				if (wasVerbose) {
+//					System.out.println("-> Package cache size = " + JavaModelManager.getJavaModelManager().cache.pkgSize()); //$NON-NLS-1$
+//					System.out.println("-> Openable cache filling ratio = " + JavaModelManager.getJavaModelManager().cache.openableFillingRatio() + "%"); //$NON-NLS-1$//$NON-NLS-2$
+//				}
+//			} finally {
+//				JavaModelManager.VERBOSE = wasVerbose;
+//			}
+//		}
+//	}
+	/**
+	 * This element is being closed.  Do any necessary cleanup.
+	 */
+	protected void closing(Object info) throws JavaModelException {
+	}
+	/**
+	 * Returns true if this handle represents the same Java element
+	 * as the given handle. By default, two handles represent the same
+	 * element if they are identical or if they represent the same type
+	 * of element, have equal names, parents, and occurrence counts.
+	 *
+	 * <p>If a subclass has other requirements for equality, this method
+	 * must be overridden.
+	 *
+	 * @see Object#equals
+	 */
+	public boolean equals(Object o) {
+		
+		if (this == o) return true;
+	
+		// Java model parent is null
+		if (fParent == null) return super.equals(o);
+	
+		if (o instanceof JavaElement) {
+			JavaElement other = (JavaElement) o;
+			if (fLEType != other.fLEType) return false;
+			
+			return fName.equals(other.fName) &&
+					fParent.equals(other.fParent) &&
+					fOccurrenceCount == other.fOccurrenceCount;
+		}
+		return false;
+	}
+	/**
+	 * Returns true if this <code>JavaElement</code> is equivalent to the given
+	 * <code>IDOMNode</code>.
+	 */
+//	protected boolean equalsDOMNode(IDOMNode node) throws JavaModelException {
+//		return false;
+//	}
+	/**
+	 * @see IJavaElement
+	 */
+//	public boolean exists() {
+//		
+//		try {
+//			getElementInfo();
+//			return true;
+//		} catch (JavaModelException e) {
+//		}
+//		return false;
+//	}
+	
+	/**
+	 * Returns the <code>IDOMNode</code> that corresponds to this <code>JavaElement</code>
+	 * or <code>null</code> if there is no corresponding node.
+	 */
+//	public IDOMNode findNode(IDOMCompilationUnit dom) {
+//		int type = getElementType();
+//		if (type == IJavaElement.COMPILATION_UNIT || 
+//			type == IJavaElement.FIELD || 
+//			type == IJavaElement.IMPORT_DECLARATION || 
+//			type == IJavaElement.INITIALIZER || 
+//			type == IJavaElement.METHOD || 
+//			type == IJavaElement.PACKAGE_DECLARATION || 
+//			type == IJavaElement.TYPE) {
+//			ArrayList path = new ArrayList();
+//			IJavaElement element = this;
+//			while (element != null && element.getElementType() != IJavaElement.COMPILATION_UNIT) {
+//				if (element.getElementType() != IJavaElement.IMPORT_CONTAINER) {
+//					// the DOM does not have import containers, so skip them
+//					path.add(0, element);
+//				}
+//				element = element.getParent();
+//			}
+//			if (path.size() == 0) {
+//				try {
+//					if (equalsDOMNode(dom)) {
+//						return dom;
+//					} else {
+//						return null;
+//					}
+//				} catch(JavaModelException e) {
+//					return null;
+//				}
+//			}
+//			return ((JavaElement) path.get(0)).followPath(path, 0, dom.getFirstChild());
+//		} else {
+//			return null;
+//		}
+//	}
+//	/**
+//	 */
+//	protected IDOMNode followPath(ArrayList path, int position, IDOMNode node) {
+//	
+//		try {
+//			if (equalsDOMNode(node)) {
+//				if (position == (path.size() - 1)) {
+//					return node;
+//				} else {
+//					if (node.getFirstChild() != null) {
+//						position++;
+//						return ((JavaElement)path.get(position)).followPath(path, position, node.getFirstChild());
+//					} else {
+//						return null;
+//					}
+//				}
+//			} else if (node.getNextNode() != null) {
+//				return followPath(path, position, node.getNextNode());
+//			} else {
+//				return null;
+//			}
+//		} catch (JavaModelException e) {
+//			return null;
+//		}
+//	
+//	}
+	/**
+	 * @see IJavaElement
+	 */
+	public IJavaElement getAncestor(int ancestorType) {
+		
+		IJavaElement element = this;
+		while (element != null) {
+			if (element.getElementType() == ancestorType)  return element;
+			element= element.getParent();
+		}
+		return null;				
+	}
+	/**
+	 * @see IParent 
+	 */
+//	public IJavaElement[] getChildren() throws JavaModelException {
+//		return ((JavaElementInfo)getElementInfo()).getChildren();
+//	}
+	/**
+	 * Returns a collection of (immediate) children of this node of the
+	 * specified type.
+	 *
+	 * @param type - one of constants defined by IJavaLanguageElementTypes
+	 */
+//	public ArrayList getChildrenOfType(int type) throws JavaModelException {
+//		IJavaElement[] children = getChildren();
+//		int size = children.length;
+//		ArrayList list = new ArrayList(size);
+//		for (int i = 0; i < size; ++i) {
+//			JavaElement elt = (JavaElement)children[i];
+//			if (elt.getElementType() == type) {
+//				list.add(elt);
+//			}
+//		}
+//		return list;
+//	}
+	/**
+	 * @see IMember
+	 */
+//	public IClassFile getClassFile() {
+//		return null;
+//	}
+//	/**
+//	 * @see IMember
+//	 */
+//	public ICompilationUnit getCompilationUnit() {
+//		return null;
+//	}
+	/**
+	 * Returns the info for this handle.  
+	 * If this element is not already open, it and all of its parents are opened.
+	 * Does not return null.
+	 * NOTE: BinaryType infos are NJOT rooted under JavaElementInfo.
+	 * @exception JavaModelException if the element is not present or not accessible
+	 */
+//	public Object getElementInfo() throws JavaModelException {
+//
+//		// workaround to ensure parent project resolved classpath is available to avoid triggering initializers
+//		// while the JavaModelManager lock is acquired (can cause deadlocks in clients)
+//		IJavaProject project = getJavaProject();
+//		if (project != null && !project.isOpen()) {
+//			// TODO: need to revisit, since deadlock could still occur if perProjectInfo is removed concurrent before entering the lock
+//			try {
+//				project.getResolvedClasspath(true); // trigger all possible container/variable initialization outside the model lock
+//			} catch (JavaModelException e) {
+//				// project is not accessible or is not a java project
+//			}
+//		}
+//
+//		// element info creation is done inside a lock on the JavaModelManager
+//		JavaModelManager manager;
+//		synchronized(manager = JavaModelManager.getJavaModelManager()){
+//			Object info = manager.getInfo(this);
+//			if (info == null) {
+//				openHierarchy();
+//				info= manager.getInfo(this);
+//				if (info == null) {
+//					throw newNotPresentException();
+//				}
+//			}
+//			return info;
+//		}
+//	}
+	/**
+	 * @see IAdaptable
+	 */
+	public String getElementName() {
+		return fName;
+	}
+	/**
+	 * @see IJavaElement
+	 */
+	public int getElementType() {
+		return fLEType;
+	}
+	/**
+	 * @see IJavaElement
+	 */
+	public String getHandleIdentifier() {
+		return getHandleMemento();
+	}
+	/**
+	 * @see JavaElement#getHandleMemento()
+	 */
+	public String getHandleMemento(){
+		StringBuffer buff= new StringBuffer(((JavaElement)getParent()).getHandleMemento());
+		buff.append(getHandleMementoDelimiter());
+		buff.append(getElementName());
+		return buff.toString();
+	}
+	/**
+	 * Returns the <code>char</code> that marks the start of this handles
+	 * contribution to a memento.
+	 */
+	protected abstract char getHandleMementoDelimiter();
+	/**
+	 * @see IJavaElement
+	 */
+	public IJavaModel getJavaModel() {
+		IJavaElement current = this;
+		do {
+			if (current instanceof IJavaModel) return (IJavaModel) current;
+		} while ((current = current.getParent()) != null);
+		return null;
+	}
+//
+//	/**
+//	 * @see IJavaElement
+//	 */
+//	public IJavaProject getJavaProject() {
+//		IJavaElement current = this;
+//		do {
+//			if (current instanceof IJavaProject) return (IJavaProject) current;
+//		} while ((current = current.getParent()) != null);
+//		return null;
+//	}
+	/**
+	 * Returns the occurrence count of the handle.
+	 */
+	protected int getOccurrenceCount() {
+		return fOccurrenceCount;
+	}
+	/*
+	 * @see IJavaElement
+	 */
+	public IOpenable getOpenable() {
+		return this.getOpenableParent();	
+	}
+	/**
+	 * Return the first instance of IOpenable in the parent
+	 * hierarchy of this element.
+	 *
+	 * <p>Subclasses that are not IOpenable's must override this method.
+	 */
+	public IOpenable getOpenableParent() {
+		
+		return (IOpenable)fParent;
+	}
+	/**
+	 * @see IJavaElement
+	 */
+	public IJavaElement getParent() {
+		return fParent;
+	}
+	
+	/**
+	 * Returns the element that is located at the given source position
+	 * in this element.  This is a helper method for <code>ICompilationUnit#getElementAt</code>,
+	 * and only works on compilation units and types. The position given is
+	 * known to be within this element's source range already, and if no finer
+	 * grained element is found at the position, this element is returned.
+	 */
+//	protected IJavaElement getSourceElementAt(int position) throws JavaModelException {
+//		if (this instanceof ISourceReference) {
+//			IJavaElement[] children = getChildren();
+//			int i;
+//			for (i = 0; i < children.length; i++) {
+//				IJavaElement aChild = children[i];
+//				if (aChild instanceof SourceRefElement) {
+//					SourceRefElement child = (SourceRefElement) children[i];
+//					ISourceRange range = child.getSourceRange();
+//					if (position < range.getOffset() + range.getLength() && position >= range.getOffset()) {
+//						if (child instanceof IParent) {
+//							return child.getSourceElementAt(position);
+//						} else {
+//							return child;
+//						}
+//					}
+//				}
+//			}
+//		} else {
+//			// should not happen
+//			Assert.isTrue(false);
+//		}
+//		return this;
+//	}
+	/**
+	 * Returns the SourceMapper facility for this element, or
+	 * <code>null</code> if this element does not have a
+	 * SourceMapper.
+	 */
+//	public SourceMapper getSourceMapper() {
+//		return ((JavaElement)getParent()).getSourceMapper();
+//	}
+
+	/**
+	 * Returns the hash code for this Java element. By default,
+	 * the hash code for an element is a combination of its name
+	 * and parent's hash code. Elements with other requirements must
+	 * override this method.
+	 */
+	public int hashCode() {
+		if (fParent == null) return super.hashCode();
+		return Util.combineHashCodes(fName.hashCode(), fParent.hashCode());
+	}
+	/**
+	 * Returns true if this element is an ancestor of the given element,
+	 * otherwise false.
+	 */
+	protected boolean isAncestorOf(IJavaElement e) {
+		IJavaElement parent= e.getParent();
+		while (parent != null && !parent.equals(this)) {
+			parent= parent.getParent();
+		}
+		return parent != null;
+	}
+	
+	/**
+	 * @see IJavaElement
+	 */
+	public boolean isReadOnly() {
+		return false;
+	}
+	/**
+	 * @see IJavaElement
+	 */
+//	public boolean isStructureKnown() throws JavaModelException {
+//		return ((JavaElementInfo)getElementInfo()).isStructureKnown();
+//	}
+//	/**
+//	 * Creates and returns and not present exception for this element.
+//	 */
+//	protected JavaModelException newNotPresentException() {
+//		return new JavaModelException(new JavaModelStatus(IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST, this));
+//	}
+//	/**
+//	 * Opens this element and all parents that are not already open.
+//	 *
+//	 * @exception JavaModelException this element is not present or accessible
+//	 */
+//	protected void openHierarchy() throws JavaModelException {
+//		if (this instanceof IOpenable) {
+//			((Openable) this).openWhenClosed(null);
+//		} else {
+//			Openable openableParent = (Openable)getOpenableParent();
+//			if (openableParent != null) {
+//				JavaElementInfo openableParentInfo = (JavaElementInfo) JavaModelManager.getJavaModelManager().getInfo((IJavaElement) openableParent);
+//				if (openableParentInfo == null) {
+//					openableParent.openWhenClosed(null);
+//				} else {
+//					throw newNotPresentException();
+//				}
+//			}
+//		}
+//	}
+	/**
+	 * This element has just been opened.  Do any necessary setup.
+	 */
+	protected void opening(Object info) {
+	}
+	/**
+	 */
+	public String readableName() {
+		return this.getElementName();
+	}
+	/**
+	 * Removes all cached info from the Java Model, including all children,
+	 * but does not close this element.
+	 */
+//	protected void removeInfo() {
+//		Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
+//		if (info != null) {
+//			if (this instanceof IParent) {
+//				IJavaElement[] children = ((JavaElementInfo)info).getChildren();
+//				for (int i = 0, size = children.length; i < size; ++i) {
+//					JavaElement child = (JavaElement) children[i];
+//					child.removeInfo();
+//				}
+//			}
+//			JavaModelManager.getJavaModelManager().removeInfo(this);
+//		}
+//	}
+//	/**
+//	 * Returns a copy of this element rooted at the given project.
+//	 */
+//	public abstract IJavaElement rootedAt(IJavaProject project);
+//	/**
+//	 * Runs a Java Model Operation
+//	 */
+//	public static void runOperation(JavaModelOperation operation, IProgressMonitor monitor) throws JavaModelException {
+//		try {
+//			if (operation.isReadOnly() || ResourcesPlugin.getWorkspace().isTreeLocked()) {
+//				operation.run(monitor);
+//			} else {
+//				// use IWorkspace.run(...) to ensure that a build will be done in autobuild mode
+//				ResourcesPlugin.getWorkspace().run(operation, monitor);
+//			}
+//		} catch (CoreException ce) {
+//			if (ce instanceof JavaModelException) {
+//				throw (JavaModelException)ce;
+//			} else {
+//				if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
+//					Throwable e= ce.getStatus().getException();
+//					if (e instanceof JavaModelException) {
+//						throw (JavaModelException) e;
+//					}
+//				}
+//				throw new JavaModelException(ce);
+//			}
+//		}
+//	}
+	/**
+	 * Sets the occurrence count of the handle.
+	 */
+	protected void setOccurrenceCount(int count) {
+		fOccurrenceCount = count;
+	}
+	protected String tabString(int tab) {
+		StringBuffer buffer = new StringBuffer();
+		for (int i = tab; i > 0; i--)
+			buffer.append("  "); //$NON-NLS-1$
+		return buffer.toString();
+	}
+	/**
+	 * Debugging purposes
+	 */
+	public String toDebugString() {
+		StringBuffer buffer = new StringBuffer();
+		this.toStringInfo(0, buffer, NO_INFO);
+		return buffer.toString();
+	}
+	/**
+	 *  Debugging purposes
+	 */
+	public String toString() {
+		StringBuffer buffer = new StringBuffer();
+		toString(0, buffer);
+		return buffer.toString();
+	}
+	/**
+	 *  Debugging purposes
+	 */
+	protected void toString(int tab, StringBuffer buffer) {
+	//	Object info = this.toStringInfo(tab, buffer);
+		Object info = null;
+		if (tab == 0) {
+			this.toStringAncestors(buffer);
+		}
+		this.toStringChildren(tab, buffer, info);
+	}
+	/**
+	 *  Debugging purposes
+	 */
+	public String toStringWithAncestors() {
+		StringBuffer buffer = new StringBuffer();
+		this.toStringInfo(0, buffer, NO_INFO);
+		this.toStringAncestors(buffer);
+		return buffer.toString();
+	}
+	/**
+	 *  Debugging purposes
+	 */
+	protected void toStringAncestors(StringBuffer buffer) {
+		JavaElement parent = (JavaElement)this.getParent();
+		if (parent != null && parent.getParent() != null) {
+			buffer.append(" [in "); //$NON-NLS-1$
+			parent.toStringInfo(0, buffer, NO_INFO);
+			parent.toStringAncestors(buffer);
+			buffer.append("]"); //$NON-NLS-1$
+		}
+	}
+	/**
+	 *  Debugging purposes
+	 */
+	protected void toStringChildren(int tab, StringBuffer buffer, Object info) {
+		if (info == null || !(info instanceof JavaElementInfo)) return;
+		IJavaElement[] children = ((JavaElementInfo)info).getChildren();
+		for (int i = 0; i < children.length; i++) {
+			buffer.append("\n"); //$NON-NLS-1$
+			((JavaElement)children[i]).toString(tab + 1, buffer);
+		}
+	}
+	/**
+	 *  Debugging purposes
+	 */
+//	public Object toStringInfo(int tab, StringBuffer buffer) {
+//		Object info = JavaModelManager.getJavaModelManager().peekAtInfo(this);
+//		this.toStringInfo(tab, buffer, info);
+//		return info;
+//	}
+	/**
+	 *  Debugging purposes
+	 */
+	protected void toStringInfo(int tab, StringBuffer buffer, Object info) {
+		buffer.append(this.tabString(tab));
+		buffer.append(getElementName());
+		if (info == null) {
+			buffer.append(" (not open)"); //$NON-NLS-1$
+		}
+	}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElementInfo.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElementInfo.java
new file mode 100644
index 0000000..532ddd3
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaElementInfo.java
@@ -0,0 +1,130 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core;
+
+import net.sourceforge.phpdt.core.IJavaElement;
+
+
+
+/**
+ * Holds cached structure and properties for a Java element.
+ * Subclassed to carry properties for specific kinds of elements.
+ */
+/* package */ class JavaElementInfo {
+
+	/**
+	 * Collection of handles of immediate children of this
+	 * object. This is an empty array if this element has
+	 * no children.
+	 */
+	protected IJavaElement[] fChildren;
+
+	/**
+	 * Shared empty collection used for efficiency.
+	 */
+	protected static IJavaElement[] fgEmptyChildren = new IJavaElement[]{};
+	/**
+	 * Is the structure of this element known
+	 * @see IJavaElement#isStructureKnown()
+	 */
+	protected boolean fIsStructureKnown = false;
+
+	/**
+	 * Shared empty collection used for efficiency.
+	 */
+	static Object[] NO_NON_JAVA_RESOURCES = new Object[] {};	
+	protected JavaElementInfo() {
+		fChildren = fgEmptyChildren;
+	}
+	public void addChild(IJavaElement child) {
+		if (fChildren == fgEmptyChildren) {
+			setChildren(new IJavaElement[] {child});
+		} else {
+			if (!includesChild(child)) {
+				setChildren(growAndAddToArray(fChildren, child));
+			}
+		}
+	}
+	public Object clone() {
+		try {
+			return super.clone();
+		}
+		catch (CloneNotSupportedException e) {
+			throw new Error();
+		}
+	}
+	public IJavaElement[] getChildren() {
+		return fChildren;
+	}
+	/**
+	 * Adds the new element to a new array that contains all of the elements of the old array.
+	 * Returns the new array.
+	 */
+	protected IJavaElement[] growAndAddToArray(IJavaElement[] array, IJavaElement addition) {
+		IJavaElement[] old = array;
+		array = new IJavaElement[old.length + 1];
+		System.arraycopy(old, 0, array, 0, old.length);
+		array[old.length] = addition;
+		return array;
+	}
+	/**
+	 * Returns <code>true</code> if this child is in my children collection
+	 */
+	protected boolean includesChild(IJavaElement child) {
+		
+		for (int i= 0; i < fChildren.length; i++) {
+			if (fChildren[i].equals(child)) {
+				return true;
+			}
+		}
+		return false;
+	}
+	/**
+	 * @see IJavaElement#isStructureKnown()
+	 */
+	public boolean isStructureKnown() {
+		return fIsStructureKnown;
+	}
+	/**
+	 * Returns an array with all the same elements as the specified array except for
+	 * the element to remove. Assumes that the deletion is contained in the array.
+	 */
+	protected IJavaElement[] removeAndShrinkArray(IJavaElement[] array, IJavaElement deletion) {
+		IJavaElement[] old = array;
+		array = new IJavaElement[old.length - 1];
+		int j = 0;
+		for (int i = 0; i < old.length; i++) {
+			if (!old[i].equals(deletion)) {
+				array[j] = old[i];
+			} else {
+				System.arraycopy(old, i + 1, array, j, old.length - (i + 1));
+				return array;
+			}
+			j++;
+		}
+		return array;
+	}
+	public void removeChild(IJavaElement child) {
+		if (includesChild(child)) {
+			setChildren(removeAndShrinkArray(fChildren, child));
+		}
+	}
+	public void setChildren(IJavaElement[] children) {
+		fChildren = children;
+	}
+	/**
+	 * Sets whether the structure of this element known
+	 * @see IJavaElement#isStructureKnown()
+	 */
+	public void setIsStructureKnown(boolean newIsStructureKnown) {
+		fIsStructureKnown = newIsStructureKnown;
+	}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaModelStatus.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaModelStatus.java
new file mode 100644
index 0000000..e895a82
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/JavaModelStatus.java
@@ -0,0 +1,451 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core;
+
+import net.sourceforge.phpdt.core.IJavaElement;
+import net.sourceforge.phpdt.core.IJavaModelStatus;
+import net.sourceforge.phpdt.core.IJavaModelStatusConstants;
+import net.sourceforge.phpeclipse.PHPCore;
+
+import org.eclipse.core.resources.IResourceStatus;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * @see IJavaModelStatus
+ */
+
+public class JavaModelStatus
+  extends Status
+  implements IJavaModelStatus, IJavaModelStatusConstants, IResourceStatus {
+
+  /**
+   * The elements related to the failure, or <code>null</code>
+   * if no elements are involved.
+   */
+  protected IJavaElement[] fElements = new IJavaElement[0];
+  
+  /**
+   * The path related to the failure, or <code>null</code>
+   * if no path is involved.
+   */
+  protected IPath fPath;
+  /**
+   * The <code>String</code> related to the failure, or <code>null</code>
+   * if no <code>String</code> is involved.
+   */
+  protected String fString;
+  /**
+   * Empty children
+   */
+  protected final static IStatus[] fgEmptyChildren = new IStatus[] {
+  };
+  protected IStatus[] fChildren = fgEmptyChildren;
+
+  /**
+  	 * Shared empty collection used for efficiency.
+  	 */
+  protected static IJavaElement[] fgObjectEmptyChildren = new IJavaElement[]{};
+  
+
+  /**
+   * Singleton OK object
+   */
+  public static final IJavaModelStatus VERIFIED_OK = new JavaModelStatus(OK, OK, Util.bind("status.OK")); //$NON-NLS-1$
+
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus() {
+    // no code for an multi-status
+    super(ERROR, PHPCore.PLUGIN_ID, 0, "JavaModelStatus", null); //$NON-NLS-1$
+  }
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(int code) {
+    super(ERROR, PHPCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$
+    //	fElements= JavaElementInfo.fgEmptyChildren;
+    fElements = fgObjectEmptyChildren;
+  }
+  /**
+   * Constructs an Java model status with the given corresponding
+   * elements.
+   */
+  public JavaModelStatus(int code, IJavaElement[] elements) {
+    super(ERROR, PHPCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$
+    fElements = elements;
+    fPath = null;
+  }
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(int code, String string) {
+    this(ERROR, code, string);
+  }
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(int severity, int code, String string) {
+    super(severity, PHPCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$
+    // fElements= JavaElementInfo.fgEmptyChildren;
+    fElements = fgObjectEmptyChildren;
+    fPath = null;
+    fString = string;
+  }
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(int code, Throwable throwable) {
+    super(ERROR, PHPCore.PLUGIN_ID, code, "JavaModelStatus", throwable); //$NON-NLS-1$
+    //	fElements= JavaElementInfo.fgEmptyChildren;
+    fElements = fgObjectEmptyChildren;
+  }
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(int code, IPath path) {
+    super(ERROR, PHPCore.PLUGIN_ID, code, "JavaModelStatus", null); //$NON-NLS-1$
+    //		fElements= JavaElementInfo.fgEmptyChildren;
+    fElements = fgObjectEmptyChildren;
+    fPath = path;
+  }
+  /**
+   * Constructs an Java model status with the given corresponding
+   * element.
+   */
+  //	public JavaModelStatus(int code, IJavaElement element) {
+  //		this(code, new IJavaElement[]{element});
+  //	}
+  /**
+   * Constructs an Java model status with the given corresponding
+   * element and string
+   */
+  //	public JavaModelStatus(int code, IJavaElement element, String string) {
+  //		this(code, new IJavaElement[]{element});
+  //		fString = string;
+  //	}
+  //	
+  //	/**
+  //	 * Constructs an Java model status with the given corresponding
+  //	 * element and path
+  //	 */
+  //	public JavaModelStatus(int code, IJavaElement element, IPath path) {
+  //		this(code, new IJavaElement[]{element});
+  //		fPath = path;
+  //	}	
+  /**
+   * Constructs an Java model status with no corresponding elements.
+   */
+  public JavaModelStatus(CoreException coreException) {
+    super(ERROR, PHPCore.PLUGIN_ID, CORE_EXCEPTION, "JavaModelStatus", coreException); //$NON-NLS-1$
+    //	fElements= JavaElementInfo.fgEmptyChildren;
+    fElements = fgObjectEmptyChildren;
+  }
+  protected int getBits() {
+    int severity = 1 << (getCode() % 100 / 33);
+    int category = 1 << ((getCode() / 100) + 3);
+    return severity | category;
+  }
+  /**
+   * @see IStatus
+   */
+  public IStatus[] getChildren() {
+    return fChildren;
+  }
+  /**
+   * @see IJavaModelStatus
+   */
+  public IJavaElement[] getElements() {
+    return fElements;
+  }
+  /**
+   * Returns the message that is relevant to the code of this status.
+   */
+  public String getMessage() {
+    Throwable exception = getException();
+    if (exception == null) {
+      switch (getCode()) {
+        case CORE_EXCEPTION :
+          return Util.bind("status.coreException"); //$NON-NLS-1$
+
+        case BUILDER_INITIALIZATION_ERROR :
+          return Util.bind("build.initializationError"); //$NON-NLS-1$
+
+        case BUILDER_SERIALIZATION_ERROR :
+          return Util.bind("build.serializationError"); //$NON-NLS-1$
+
+        case DEVICE_PATH :
+          return Util.bind("status.cannotUseDeviceOnPath", getPath().toString()); //$NON-NLS-1$
+
+        case DOM_EXCEPTION :
+          return Util.bind("status.JDOMError"); //$NON-NLS-1$
+
+//          				case ELEMENT_DOES_NOT_EXIST:
+//          					return Util.bind("element.doesNotExist",((JavaElement)fElements[0]).toStringWithAncestors()); //$NON-NLS-1$
+
+        case EVALUATION_ERROR :
+          return Util.bind("status.evaluationError", fString); //$NON-NLS-1$
+
+        case INDEX_OUT_OF_BOUNDS :
+          return Util.bind("status.indexOutOfBounds"); //$NON-NLS-1$
+
+        case INVALID_CONTENTS :
+          return Util.bind("status.invalidContents"); //$NON-NLS-1$
+
+          //				case INVALID_DESTINATION:
+          //					return Util.bind("status.invalidDestination", ((JavaElement)fElements[0]).toStringWithAncestors()); //$NON-NLS-1$
+          //
+          //				case INVALID_ELEMENT_TYPES:
+          //					StringBuffer buff= new StringBuffer(Util.bind("operation.notSupported")); //$NON-NLS-1$
+          //					for (int i= 0; i < fElements.length; i++) {
+          //						if (i > 0) {
+          //							buff.append(", "); //$NON-NLS-1$
+          //						}
+          //						buff.append(((JavaElement)fElements[i]).toStringWithAncestors());
+          //					}
+          //					return buff.toString();
+
+        case INVALID_NAME :
+          return Util.bind("status.invalidName", fString); //$NON-NLS-1$
+
+        case INVALID_PACKAGE :
+          return Util.bind("status.invalidPackage", fString); //$NON-NLS-1$
+
+        case INVALID_PATH :
+          if (fString != null) {
+            return fString;
+          } else {
+            return Util.bind("status.invalidPath", getPath() == null ? "null" : getPath().toString()); //$NON-NLS-1$ //$NON-NLS-2$
+          }
+
+        case INVALID_PROJECT :
+          return Util.bind("status.invalidProject", fString); //$NON-NLS-1$
+
+        case INVALID_RESOURCE :
+          return Util.bind("status.invalidResource", fString); //$NON-NLS-1$
+
+        case INVALID_RESOURCE_TYPE :
+          return Util.bind("status.invalidResourceType", fString); //$NON-NLS-1$
+
+          //				case INVALID_SIBLING:
+          //					if (fString != null) {
+          //						return Util.bind("status.invalidSibling", fString); //$NON-NLS-1$
+          //					} else {
+          //						return Util.bind("status.invalidSibling", ((JavaElement)fElements[0]).toStringWithAncestors()); //$NON-NLS-1$
+          //					}
+
+        case IO_EXCEPTION :
+          return Util.bind("status.IOException"); //$NON-NLS-1$
+
+          //				case NAME_COLLISION:
+          //					if (fElements != null && fElements.length > 0) {
+          //						IJavaElement element = fElements[0];
+          //						String name = element.getElementName();
+          //						if (element instanceof IPackageFragment && name.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
+          //							return Util.bind("operation.cannotRenameDefaultPackage"); //$NON-NLS-1$
+          //						}
+          //					}
+          //					if (fString != null) {
+          //						return fString;
+          //					} else {
+          //						return Util.bind("status.nameCollision", ""); //$NON-NLS-1$ //$NON-NLS-2$
+          //					}
+        case NO_ELEMENTS_TO_PROCESS :
+          return Util.bind("operation.needElements"); //$NON-NLS-1$
+
+        case NULL_NAME :
+          return Util.bind("operation.needName"); //$NON-NLS-1$
+
+        case NULL_PATH :
+          return Util.bind("operation.needPath"); //$NON-NLS-1$
+
+        case NULL_STRING :
+          return Util.bind("operation.needString"); //$NON-NLS-1$
+
+          //				case PATH_OUTSIDE_PROJECT:
+          //					return Util.bind("operation.pathOutsideProject", fString, ((JavaElement)fElements[0]).toStringWithAncestors()); //$NON-NLS-1$
+          //
+          //				case READ_ONLY:
+          //					IJavaElement element = fElements[0];
+          //					String name = element.getElementName();
+          //					if (element instanceof IPackageFragment && name.equals(IPackageFragment.DEFAULT_PACKAGE_NAME)) {
+          //						return Util.bind("status.defaultPackageReadOnly"); //$NON-NLS-1$
+          //					}
+          //					return  Util.bind("status.readOnly", name); //$NON-NLS-1$
+
+        case RELATIVE_PATH :
+          return Util.bind("operation.needAbsolutePath", getPath().toString()); //$NON-NLS-1$
+
+        case TARGET_EXCEPTION :
+          return Util.bind("status.targetException"); //$NON-NLS-1$
+
+        case UPDATE_CONFLICT :
+          return Util.bind("status.updateConflict"); //$NON-NLS-1$
+
+        case NO_LOCAL_CONTENTS :
+          return Util.bind("status.noLocalContents", getPath().toString()); //$NON-NLS-1$
+
+          //				case CP_CONTAINER_PATH_UNBOUND:
+          //					IPath path = this.fPath;
+          //					IJavaProject javaProject = (IJavaProject)fElements[0];
+          //					ClasspathContainerInitializer initializer = PHPCore.getClasspathContainerInitializer(path.segment(0));
+          //					String description = null;
+          //					if (initializer != null) description = initializer.getDescription(path, javaProject);
+          //					if (description == null) description = path.makeRelative().toString();
+          //					return Util.bind("classpath.unboundContainerPath", description); //$NON-NLS-1$
+          //
+          //				case INVALID_CP_CONTAINER_ENTRY:
+          //					path = this.fPath;
+          //					javaProject = (IJavaProject)fElements[0];
+          //					IClasspathContainer container = null;
+          //					description = null;
+          //					try {
+          //						container = PHPCore.getClasspathContainer(path, javaProject);
+          //					} catch(JavaModelException e){
+          //					}
+          //					if (container == null) {
+          //						 initializer = PHPCore.getClasspathContainerInitializer(path.segment(0));
+          //						if (initializer != null) description = initializer.getDescription(path, javaProject);
+          //					} else {
+          //						description = container.getDescription();
+          //					}
+          //					if (description == null) description = path.makeRelative().toString();
+          //					return Util.bind("classpath.invalidContainer", description); //$NON-NLS-1$
+          //
+          //			case CP_VARIABLE_PATH_UNBOUND:
+          //					path = this.fPath;
+          //					return Util.bind("classpath.unboundVariablePath", path.makeRelative().toString()); //$NON-NLS-1$
+          //					
+          //			case CLASSPATH_CYCLE: 
+          //					javaProject = (IJavaProject)fElements[0];
+          //					return Util.bind("classpath.cycle", javaProject.getElementName()); //$NON-NLS-1$
+
+          //			case DISABLED_CP_EXCLUSION_PATTERNS:
+          //					path = this.fPath;
+          //					return Util.bind("classpath.disabledExclusionPatterns", path.makeRelative().toString()); //$NON-NLS-1$
+          //
+          //			case DISABLED_CP_MULTIPLE_OUTPUT_LOCATIONS:
+          //					path = this.fPath;
+          //					return Util.bind("classpath.disabledMultipleOutputLocations", path.makeRelative().toString()); //$NON-NLS-1$
+      }
+      if (fString != null) {
+        return fString;
+      } else {
+        return ""; // //$NON-NLS-1$
+      }
+    } else {
+      String message = exception.getMessage();
+      if (message != null) {
+        return message;
+      } else {
+        return exception.toString();
+      }
+    }
+  }
+  /**
+   * @see IJavaModelStatus#getPath()
+   */
+  public IPath getPath() {
+    return fPath;
+  }
+  /**
+   * @see IStatus#getSeverity()
+   */
+  public int getSeverity() {
+    if (fChildren == fgEmptyChildren)
+      return super.getSeverity();
+    int severity = -1;
+    for (int i = 0, max = fChildren.length; i < max; i++) {
+      int childrenSeverity = fChildren[i].getSeverity();
+      if (childrenSeverity > severity) {
+        severity = childrenSeverity;
+      }
+    }
+    return severity;
+  }
+  /**
+   * @see IJavaModelStatus#getString()
+   * @deprecated
+   */
+  public String getString() {
+    return fString;
+  }
+  /**
+   * @see IJavaModelStatus#isDoesNotExist()
+   */
+  public boolean isDoesNotExist() {
+    return getCode() == ELEMENT_DOES_NOT_EXIST;
+  }
+  /**
+   * @see IStatus#isMultiStatus()
+   */
+  public boolean isMultiStatus() {
+    return fChildren != fgEmptyChildren;
+  }
+  /**
+   * @see IStatus#isOK()
+   */
+  public boolean isOK() {
+    return getCode() == OK;
+  }
+  /**
+   * @see IStatus#matches(int)
+   */
+  public boolean matches(int mask) {
+    if (!isMultiStatus()) {
+      return matches(this, mask);
+    } else {
+      for (int i = 0, max = fChildren.length; i < max; i++) {
+        if (matches((JavaModelStatus) fChildren[i], mask))
+          return true;
+      }
+      return false;
+    }
+  }
+  /**
+   * Helper for matches(int).
+   */
+  protected boolean matches(JavaModelStatus status, int mask) {
+    int severityMask = mask & 0x7;
+    int categoryMask = mask & ~0x7;
+    int bits = status.getBits();
+    return ((severityMask == 0) || (bits & severityMask) != 0)
+      && ((categoryMask == 0) || (bits & categoryMask) != 0);
+  }
+  /**
+   * Creates and returns a new <code>IJavaModelStatus</code> that is a
+   * a multi-status status.
+   *
+   * @see IStatus#isMultiStatus()
+   */
+  public static IJavaModelStatus newMultiStatus(IJavaModelStatus[] children) {
+    JavaModelStatus jms = new JavaModelStatus();
+    jms.fChildren = children;
+    return jms;
+  }
+  /**
+   * Returns a printable representation of this exception for debugging
+   * purposes.
+   */
+  public String toString() {
+    if (this == VERIFIED_OK) {
+      return "JavaModelStatus[OK]"; //$NON-NLS-1$
+    }
+    StringBuffer buffer = new StringBuffer();
+    buffer.append("Java Model Status ["); //$NON-NLS-1$
+    buffer.append(getMessage());
+    buffer.append("]"); //$NON-NLS-1$
+    return buffer.toString();
+  }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/LRUCacheEnumerator.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/LRUCacheEnumerator.java
new file mode 100644
index 0000000..8a04b28
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/LRUCacheEnumerator.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core;
+
+import java.util.Enumeration;
+
+/**
+ *	The <code>LRUCacheEnumerator</code> returns its elements in 
+ *	the order they are found in the <code>LRUCache</code>, with the
+ *	most recent elements first.
+ *
+ *	Once the enumerator is created, elements which are later added 
+ *	to the cache are not returned by the enumerator.  However,
+ *	elements returned from the enumerator could have been closed 
+ *	by the cache.
+ */
+public class LRUCacheEnumerator implements Enumeration {
+	/**
+	 *	Current element;
+	 */
+	protected LRUEnumeratorElement fElementQueue;
+
+	public static class LRUEnumeratorElement {
+		/**
+		 *	Value returned by <code>nextElement()</code>;
+		 */
+		public Object fValue;
+		
+		/**
+		 *	Next element
+		 */
+		public LRUEnumeratorElement fNext;
+
+		/**
+		 * Constructor
+		 */
+		public LRUEnumeratorElement(Object value) {
+			fValue = value;
+		}
+	}
+/**
+ *	Creates a CacheEnumerator on the list of <code>LRUEnumeratorElements</code>.
+ */
+public LRUCacheEnumerator(LRUEnumeratorElement firstElement) {
+	fElementQueue = firstElement;
+}
+/**
+ * Returns true if more elements exist.
+ */
+public boolean hasMoreElements() {
+	return fElementQueue != null;
+}
+/**
+ * Returns the next element.
+ */
+public Object nextElement() {
+	Object temp = fElementQueue.fValue;
+	fElementQueue = fElementQueue.fNext;
+	return temp;
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/OverflowingLRUCache.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/OverflowingLRUCache.java
new file mode 100644
index 0000000..8b415c0
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/OverflowingLRUCache.java
@@ -0,0 +1,426 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core;
+
+import java.util.Enumeration;
+import java.util.Iterator;
+
+import net.sourceforge.phpdt.core.util.LRUCache;
+
+/**
+ *	The <code>OverflowingLRUCache</code> is an LRUCache which attempts
+ *	to maintain a size equal or less than its <code>fSpaceLimit</code>
+ *	by removing the least recently used elements.
+ *
+ *	<p>The cache will remove elements which successfully close and all
+ *	elements which are explicitly removed.
+ *
+ *	<p>If the cache cannot remove enough old elements to add new elements
+ *	it will grow beyond <code>fSpaceLimit</code>. Later, it will attempt to 
+ *	shink back to the maximum space limit.
+ *
+ *	The method <code>close</code> should attempt to close the element.  If
+ *	the element is successfully closed it will return true and the element will
+ *	be removed from the cache.  Otherwise the element will remain in the cache.
+ *
+ *	<p>The cache implicitly attempts shrinks on calls to <code>put</code>and
+ *	<code>setSpaceLimit</code>.  Explicitly calling the <code>shrink</code> method
+ *	will also cause the cache to attempt to shrink.
+ *
+ *	<p>The cache calculates the used space of all elements which implement 
+ *	<code>ILRUCacheable</code>.  All other elements are assumed to be of size one.
+ *
+ *	<p>Use the <code>#peek(Object)</code> and <code>#disableTimestamps()</code> method to
+ *	circumvent the timestamp feature of the cache.  This feature is intended to be used
+ *	only when the <code>#close(LRUCacheEntry)</code> method causes changes to the cache.  
+ *	For example, if a parent closes its children when </code>#close(LRUCacheEntry)</code> is called, 
+ *	it should be careful not to change the LRU linked list.  It can be sure it is not causing 
+ *	problems by calling <code>#peek(Object)</code> instead of <code>#get(Object)</code> method.
+ *	
+ *	@see LRUCache
+ */
+public abstract class OverflowingLRUCache extends LRUCache {
+	/**
+	 * Indicates if the cache has been over filled and by how much.
+	 */
+	protected int fOverflow = 0;
+	/**
+	 *	Indicates whether or not timestamps should be updated
+	 */
+	protected boolean fTimestampsOn = true;
+	/**
+	 *	Indicates how much space should be reclaimed when the cache overflows.
+	 *	Inital load factor of one third.
+	 */
+	protected double fLoadFactor = 0.333;
+/**
+ * Creates a OverflowingLRUCache. 
+ * @param size Size limit of cache.
+ */
+public OverflowingLRUCache(int size) {
+	this(size, 0);
+}
+/**
+ * Creates a OverflowingLRUCache. 
+ * @param size Size limit of cache.
+ * @param overflow Size of the overflow.
+ */
+public OverflowingLRUCache(int size, int overflow) {
+	super(size);
+	fOverflow = overflow;
+}
+	/**
+	 * Returns a new cache containing the same contents.
+	 *
+	 * @return New copy of this object.
+	 */
+	public Object clone() {
+		
+		OverflowingLRUCache newCache = (OverflowingLRUCache)newInstance(fSpaceLimit, fOverflow);
+		LRUCacheEntry qEntry;
+		
+		/* Preserve order of entries by copying from oldest to newest */
+		qEntry = this.fEntryQueueTail;
+		while (qEntry != null) {
+			newCache.privateAdd (qEntry._fKey, qEntry._fValue, qEntry._fSpace);
+			qEntry = qEntry._fPrevious;
+		}
+		return newCache;
+	}
+/**
+ * Returns true if the element is successfully closed and
+ * removed from the cache, otherwise false.
+ *
+ * <p>NOTE: this triggers an external remove from the cache
+ * by closing the obejct.
+ *
+ */
+protected abstract boolean close(LRUCacheEntry entry);
+	/**
+	 *	Returns an enumerator of the values in the cache with the most
+	 *	recently used first.
+	 */
+	public Enumeration elements() {
+		if (fEntryQueue == null)
+			return new LRUCacheEnumerator(null);
+		LRUCacheEnumerator.LRUEnumeratorElement head = 
+			new LRUCacheEnumerator.LRUEnumeratorElement(fEntryQueue._fValue);
+		LRUCacheEntry currentEntry = fEntryQueue._fNext;
+		LRUCacheEnumerator.LRUEnumeratorElement currentElement = head;
+		while(currentEntry != null) {
+			currentElement.fNext = new LRUCacheEnumerator.LRUEnumeratorElement(currentEntry._fValue);
+			currentElement = currentElement.fNext;
+			
+			currentEntry = currentEntry._fNext;
+		}
+		return new LRUCacheEnumerator(head);
+	}
+	public double fillingRatio() {
+		return (fCurrentSpace + fOverflow) * 100.0 / fSpaceLimit;
+	}
+	/**
+	 * For internal testing only.
+	 * This method exposed only for testing purposes!
+	 *
+	 * @return Hashtable of entries
+	 */
+	public java.util.Hashtable getEntryTable() {
+		return fEntryTable;
+	}
+/**
+ * Returns the load factor for the cache.  The load factor determines how 
+ * much space is reclaimed when the cache exceeds its space limit.
+ * @return double
+ */
+public double getLoadFactor() {
+	return fLoadFactor;
+}
+	/**
+	 *	@return The space by which the cache has overflown.
+	 */
+	public int getOverflow() {
+		return fOverflow;
+	}
+	/**
+	 * Ensures there is the specified amount of free space in the receiver,
+	 * by removing old entries if necessary.  Returns true if the requested space was
+	 * made available, false otherwise.  May not be able to free enough space
+	 * since some elements cannot be removed until they are saved.
+	 *
+	 * @param space Amount of space to free up
+	 */
+	protected boolean makeSpace(int space) {
+	
+		int limit = fSpaceLimit;
+		if (fOverflow == 0) {
+			/* if space is already available */
+			if (fCurrentSpace + space <= limit) {
+				return true;
+			}
+		}
+	
+		/* Free up space by removing oldest entries */
+		int spaceNeeded = (int)((1 - fLoadFactor) * fSpaceLimit);
+		spaceNeeded = (spaceNeeded > space) ? spaceNeeded : space;
+		LRUCacheEntry entry = fEntryQueueTail;
+	
+		while (fCurrentSpace + spaceNeeded > limit && entry != null) {
+			this.privateRemoveEntry(entry, false, false);
+			entry = entry._fPrevious;
+		}
+	
+		/* check again, since we may have aquired enough space */
+		if (fCurrentSpace + space <= limit) {
+			fOverflow = 0;
+			return true;
+		}
+	
+		/* update fOverflow */
+		fOverflow = fCurrentSpace + space - limit;
+		return false;
+	}
+	/**
+	 * Returns a new instance of the reciever.
+	 */
+	protected abstract LRUCache newInstance(int size, int overflow);
+	/**
+	 * Answers the value in the cache at the given key.
+	 * If the value is not in the cache, returns null
+	 *
+	 * This function does not modify timestamps.
+	 */
+	public Object peek(Object key) {
+		
+		LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key);
+		if (entry == null) {
+			return null;
+		}
+		return entry._fValue;
+	}
+/**
+ * For testing purposes only
+ */
+public void printStats() {
+	int forwardListLength = 0;
+	LRUCacheEntry entry = fEntryQueue;
+	while(entry != null) {
+		forwardListLength++;
+		entry = entry._fNext;
+	}
+	System.out.println("Forward length: " + forwardListLength); //$NON-NLS-1$
+	
+	int backwardListLength = 0;
+	entry = fEntryQueueTail;
+	while(entry != null) {
+		backwardListLength++;
+		entry = entry._fPrevious;
+	}
+	System.out.println("Backward length: " + backwardListLength); //$NON-NLS-1$
+
+	Enumeration keys = fEntryTable.keys();
+	class Temp {
+		public Class fClass;
+		public int fCount;
+		public Temp(Class aClass) {
+			fClass = aClass;
+			fCount = 1;
+		}
+		public String toString() {
+			return "Class: " + fClass + " has " + fCount + " entries."; //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-1$
+		}
+	}
+	java.util.HashMap h = new java.util.HashMap();
+	while(keys.hasMoreElements()) {
+		entry = (LRUCacheEntry)fEntryTable.get(keys.nextElement());
+		Class key = entry._fValue.getClass();
+		Temp t = (Temp)h.get(key);
+		if (t == null) {
+			h.put(key, new Temp(key));
+		} else {
+			t.fCount++;
+		}
+	}
+
+	for (Iterator iter = h.keySet().iterator(); iter.hasNext();){
+		System.out.println(h.get(iter.next()));
+	}
+}
+	/**
+	 *	Removes the entry from the entry queue.
+	 *	Calls <code>privateRemoveEntry</code> with the external functionality enabled.
+	 *
+	 * @param shuffle indicates whether we are just shuffling the queue 
+	 * (in which case, the entry table is not modified).
+	 */
+	protected void privateRemoveEntry (LRUCacheEntry entry, boolean shuffle) {
+		privateRemoveEntry(entry, shuffle, true);
+	}
+/**
+ *	Removes the entry from the entry queue.  If <i>external</i> is true, the entry is removed
+ *	without checking if it can be removed.  It is assumed that the client has already closed
+ *	the element it is trying to remove (or will close it promptly).
+ *
+ *	If <i>external</i> is false, and the entry could not be closed, it is not removed and the 
+ *	pointers are not changed.
+ *
+ *	@param shuffle indicates whether we are just shuffling the queue 
+ *	(in which case, the entry table is not modified).
+ */
+protected void privateRemoveEntry(LRUCacheEntry entry, boolean shuffle, boolean external) {
+
+	if (!shuffle) {
+		if (external) {
+			fEntryTable.remove(entry._fKey);			
+			fCurrentSpace -= entry._fSpace;
+			privateNotifyDeletionFromCache(entry);
+		} else {
+			if (!close(entry)) return;
+			// buffer close will recursively call #privateRemoveEntry with external==true
+			// thus entry will already be removed if reaching this point.
+			if (fEntryTable.get(entry._fKey) == null){
+				return;
+			} else {
+				// basic removal
+				fEntryTable.remove(entry._fKey);			
+				fCurrentSpace -= entry._fSpace;
+				privateNotifyDeletionFromCache(entry);
+			}
+		}
+	}
+	LRUCacheEntry previous = entry._fPrevious;
+	LRUCacheEntry next = entry._fNext;
+		
+	/* if this was the first entry */
+	if (previous == null) {
+		fEntryQueue = next;
+	} else {
+		previous._fNext = next;
+	}
+	/* if this was the last entry */
+	if (next == null) {
+		fEntryQueueTail = previous;
+	} else {
+		next._fPrevious = previous;
+	}
+}
+	/**
+	 * Sets the value in the cache at the given key. Returns the value.
+	 *
+	 * @param key Key of object to add.
+	 * @param value Value of object to add.
+	 * @return added value.
+	 */
+	public Object put(Object key, Object value) {
+		/* attempt to rid ourselves of the overflow, if there is any */
+		if (fOverflow > 0)
+			shrink();
+			
+		/* Check whether there's an entry in the cache */
+		int newSpace = spaceFor (key, value);
+		LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get (key);
+		
+		if (entry != null) {
+			
+			/**
+			 * Replace the entry in the cache if it would not overflow
+			 * the cache.  Otherwise flush the entry and re-add it so as 
+			 * to keep cache within budget
+			 */
+			int oldSpace = entry._fSpace;
+			int newTotal = fCurrentSpace - oldSpace + newSpace;
+			if (newTotal <= fSpaceLimit) {
+				updateTimestamp (entry);
+				entry._fValue = value;
+				entry._fSpace = newSpace;
+				fCurrentSpace = newTotal;
+				fOverflow = 0;
+				return value;
+			} else {
+				privateRemoveEntry (entry, false, false);
+			}
+		}
+		
+		// attempt to make new space
+		makeSpace(newSpace);
+		
+		// add without worring about space, it will
+		// be handled later in a makeSpace call
+		privateAdd (key, value, newSpace);
+		
+		return value;
+	}
+	/**
+	 * Removes and returns the value in the cache for the given key.
+	 * If the key is not in the cache, returns null.
+	 *
+	 * @param key Key of object to remove from cache.
+	 * @return Value removed from cache.
+	 */
+	public Object remove(Object key) {
+		return removeKey(key);
+	}
+/**
+ * Sets the load factor for the cache.  The load factor determines how 
+ * much space is reclaimed when the cache exceeds its space limit.
+ * @param newLoadFactor double
+ * @throws IllegalArgumentException when the new load factor is not in (0.0, 1.0]
+ */
+public void setLoadFactor(double newLoadFactor) throws IllegalArgumentException {
+	if(newLoadFactor <= 1.0 && newLoadFactor > 0.0)
+		fLoadFactor = newLoadFactor;
+	else
+		throw new IllegalArgumentException(Util.bind("cache.invalidLoadFactor")); //$NON-NLS-1$
+}
+	/**
+	 * Sets the maximum amount of space that the cache can store
+	 *
+	 * @param limit Number of units of cache space
+	 */
+	public void setSpaceLimit(int limit) {
+		if (limit < fSpaceLimit) {
+			makeSpace(fSpaceLimit - limit);
+		}
+		fSpaceLimit = limit;
+	}
+	/**
+	 * Attempts to shrink the cache if it has overflown.
+	 * Returns true if the cache shrinks to less than or equal to <code>fSpaceLimit</code>.
+	 */
+	public boolean shrink() {
+		if (fOverflow > 0)
+			return makeSpace(0);
+		return true;
+	}
+/**
+ * Returns a String that represents the value of this object.  This method
+ * is for debugging purposes only.
+ */
+public String toString() {
+	return 
+		"OverflowingLRUCache " + this.fillingRatio() + "% full\n" + //$NON-NLS-1$ //$NON-NLS-2$
+		this.toStringContents();
+}
+/**
+ * Updates the timestamp for the given entry, ensuring that the queue is 
+ * kept in correct order.  The entry must exist.
+ *
+ * <p>This method will do nothing if timestamps have been disabled.
+ */
+protected void updateTimestamp(LRUCacheEntry entry) {
+	if (fTimestampsOn) {
+		entry._fTimestamp = fTimestampCounter++;
+		if (fEntryQueue != entry) {
+			this.privateRemoveEntry(entry, true);
+			this.privateAddEntry(entry, true);
+		}
+	}
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Util.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Util.java
new file mode 100644
index 0000000..6e68873
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/Util.java
@@ -0,0 +1,1352 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core;
+
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.StringTokenizer;
+
+import net.sourceforge.phpdt.core.JavaModelException;
+import net.sourceforge.phpdt.core.compiler.CharOperation;
+import net.sourceforge.phpdt.internal.core.util.CharArrayBuffer;
+import net.sourceforge.phpdt.internal.corext.Assert;
+import net.sourceforge.phpeclipse.PHPCore;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Provides convenient utility methods to other types in this package.
+ */
+public class Util {
+
+	private final static char[] DOUBLE_QUOTES = "''".toCharArray(); //$NON-NLS-1$
+	private final static char[] SINGLE_QUOTE = "'".toCharArray(); //$NON-NLS-1$
+	private static final String ARGUMENTS_DELIMITER = "#"; //$NON-NLS-1$
+	private static final String EMPTY_ARGUMENT = "   "; //$NON-NLS-1$
+
+	public interface Comparable {
+		/**
+		 * Returns 0 if this and c are equal, >0 if this is greater than c,
+		 * or <0 if this is less than c.
+		 */
+		int compareTo(Comparable c);
+	}
+
+	public interface Comparer {
+		/**
+		 * Returns 0 if a and b are equal, >0 if a is greater than b,
+		 * or <0 if a is less than b.
+		 */
+		int compare(Object a, Object b);
+	}
+	
+	public interface Displayable {
+		String displayString(Object o);
+	}
+	
+	public static final String[] fgEmptyStringArray = new String[0];
+
+	/**
+	 * Are we running JDK 1.1?
+	 */
+	private static boolean JDK1_1 = false;
+
+	/* Bundle containing messages */
+	protected static ResourceBundle bundle;
+	private final static String bundleName = "org.eclipse.jdt.internal.core.messages"; //$NON-NLS-1$
+
+	public final static char[] SUFFIX_class = ".class".toCharArray(); //$NON-NLS-1$
+	public final static char[] SUFFIX_CLASS = ".CLASS".toCharArray(); //$NON-NLS-1$
+	public final static char[] SUFFIX_java = ".java".toCharArray(); //$NON-NLS-1$
+	public final static char[] SUFFIX_JAVA = ".JAVA".toCharArray(); //$NON-NLS-1$
+	public final static char[] SUFFIX_jar = ".jar".toCharArray(); //$NON-NLS-1$
+	public final static char[] SUFFIX_JAR = ".JAR".toCharArray(); //$NON-NLS-1$
+	public final static char[] SUFFIX_zip = ".zip".toCharArray(); //$NON-NLS-1$
+	public final static char[] SUFFIX_ZIP = ".ZIP".toCharArray(); //$NON-NLS-1$
+
+	static {
+		String ver = System.getProperty("java.version"); //$NON-NLS-1$
+		JDK1_1 = ((ver != null) && ver.startsWith("1.1")); //$NON-NLS-1$
+		relocalize();
+	}	
+	
+	/**
+	 * Lookup the message with the given ID in this catalog 
+	 */
+	public static String bind(String id) {
+		return bind(id, (String[])null);
+	}
+	
+	/**
+	 * Lookup the message with the given ID in this catalog and bind its
+	 * substitution locations with the given string values.
+	 */
+	public static String bind(String id, String[] bindings) {
+		if (id == null)
+			return "No message available"; //$NON-NLS-1$
+		String message = null;
+		try {
+			message = bundle.getString(id);
+		} catch (MissingResourceException e) {
+			// If we got an exception looking for the message, fail gracefully by just returning
+			// the id we were looking for.  In most cases this is semi-informative so is not too bad.
+			return "Missing message: " + id + " in: " + bundleName; //$NON-NLS-2$ //$NON-NLS-1$
+		}
+		// for compatibility with MessageFormat which eliminates double quotes in original message
+		char[] messageWithNoDoubleQuotes =
+		CharOperation.replace(message.toCharArray(), DOUBLE_QUOTES, SINGLE_QUOTE);
+		message = new String(messageWithNoDoubleQuotes);
+	
+		if (bindings == null)
+			return message;
+	
+		int length = message.length();
+		int start = -1;
+		int end = length;
+		StringBuffer output = new StringBuffer(80);
+		while (true) {
+			if ((end = message.indexOf('{', start)) > -1) {
+				output.append(message.substring(start + 1, end));
+				if ((start = message.indexOf('}', end)) > -1) {
+					int index = -1;
+					try {
+						index = Integer.parseInt(message.substring(end + 1, start));
+						output.append(bindings[index]);
+					} catch (NumberFormatException nfe) {
+						output.append(message.substring(end + 1, start + 1));
+					} catch (ArrayIndexOutOfBoundsException e) {
+						output.append("{missing " + Integer.toString(index) + "}"); //$NON-NLS-2$ //$NON-NLS-1$
+					}
+				} else {
+					output.append(message.substring(end, length));
+					break;
+				}
+			} else {
+				output.append(message.substring(start + 1, length));
+				break;
+			}
+		}
+		return output.toString();
+	}
+
+	/**
+	 * Lookup the message with the given ID in this catalog and bind its
+	 * substitution locations with the given string.
+	 */
+	public static String bind(String id, String binding) {
+		return bind(id, new String[] {binding});
+	}
+	
+	/**
+	 * Lookup the message with the given ID in this catalog and bind its
+	 * substitution locations with the given strings.
+	 */
+	public static String bind(String id, String binding1, String binding2) {
+		return bind(id, new String[] {binding1, binding2});
+	}
+
+	/**
+	 * Checks the type signature in String sig, 
+	 * starting at start and ending before end (end is not included).
+	 * Returns the index of the character immediately after the signature if valid,
+	 * or -1 if not valid.
+	 */
+	private static int checkTypeSignature(String sig, int start, int end, boolean allowVoid) {
+		if (start >= end) return -1;
+		int i = start;
+		char c = sig.charAt(i++);
+		int nestingDepth = 0;
+		while (c == '[') {
+			++nestingDepth;
+			if (i >= end) return -1;
+			c = sig.charAt(i++);
+		}
+		switch (c) {
+			case 'B':
+			case 'C': 
+			case 'D':
+			case 'F':
+			case 'I':
+			case 'J':
+			case 'S': 
+			case 'Z':
+				break;
+			case 'V':
+				if (!allowVoid) return -1;
+				// array of void is not allowed
+				if (nestingDepth != 0) return -1;
+				break;
+			case 'L':
+				int semicolon = sig.indexOf(';', i);
+				// Must have at least one character between L and ;
+				if (semicolon <= i || semicolon >= end) return -1;
+				i = semicolon + 1;
+				break;
+			default:
+				return -1;
+		}
+		return i;
+	}
+	
+	/**
+	 * Combines two hash codes to make a new one.
+	 */
+	public static int combineHashCodes(int hashCode1, int hashCode2) {
+		return hashCode1 * 17 + hashCode2;
+	}
+	
+	/**
+	 * Compares two byte arrays.  
+	 * Returns <0 if a byte in a is less than the corresponding byte in b, or if a is shorter, or if a is null.
+	 * Returns >0 if a byte in a is greater than the corresponding byte in b, or if a is longer, or if b is null.
+	 * Returns 0 if they are equal or both null.
+	 */
+	public static int compare(byte[] a, byte[] b) {
+		if (a == b)
+			return 0;
+		if (a == null)
+			return -1;
+		if (b == null)
+			return 1;
+		int len = Math.min(a.length, b.length);
+		for (int i = 0; i < len; ++i) {
+			int diff = a[i] - b[i];
+			if (diff != 0)
+				return diff;
+		}
+		if (a.length > len)
+			return 1;
+		if (b.length > len)
+			return -1;
+		return 0;
+	}
+
+	/**
+	 * Compares two char arrays lexicographically. 
+	 * The comparison is based on the Unicode value of each character in
+	 * the char arrays. 
+	 * @return  the value <code>0</code> if a is equal to
+	 *          b; a value less than <code>0</code> if a
+	 *          is lexicographically less than b; and a
+	 *          value greater than <code>0</code> if a is
+	 *          lexicographically greater than b.
+	 */
+	public static int compare(char[] v1, char[] v2) {
+		int len1 = v1.length;
+		int len2 = v2.length;
+		int n = Math.min(len1, len2);
+		int i = 0;
+		while (n-- != 0) {
+			if (v1[i] != v2[i]) {
+				return v1[i] - v2[i];
+			}
+			++i;
+		}
+		return len1 - len2;
+	}
+
+	/**
+	 * Concatenate two strings with a char in between.
+	 * @see #concat(String, String)
+	 */
+	public static String concat(String s1, char c, String s2) {
+		if (s1 == null) s1 = "null"; //$NON-NLS-1$
+		if (s2 == null) s2 = "null"; //$NON-NLS-1$
+		int l1 = s1.length();
+		int l2 = s2.length();
+		char[] buf = new char[l1 + 1 + l2];
+		s1.getChars(0, l1, buf, 0);
+		buf[l1] = c;
+		s2.getChars(0, l2, buf, l1 + 1);
+		return new String(buf);
+	}
+	
+	/**
+	 * Concatenate two strings.
+	 * Much faster than using +, which:
+	 * 		- creates a StringBuffer,
+	 * 		- which is synchronized,
+	 * 		- of default size, so the resulting char array is
+	 *        often larger than needed.
+	 * This implementation creates an extra char array, since the
+	 * String constructor copies its argument, but there's no way around this.
+	 */
+	public static String concat(String s1, String s2) {
+		if (s1 == null) s1 = "null"; //$NON-NLS-1$
+		if (s2 == null) s2 = "null"; //$NON-NLS-1$
+		int l1 = s1.length();
+		int l2 = s2.length();
+		char[] buf = new char[l1 + l2];
+		s1.getChars(0, l1, buf, 0);
+		s2.getChars(0, l2, buf, l1);
+		return new String(buf);
+	}
+
+	/**
+	 * Concatenate three strings.
+	 * @see #concat(String, String)
+	 */
+	public static String concat(String s1, String s2, String s3) {
+		if (s1 == null) s1 = "null"; //$NON-NLS-1$
+		if (s2 == null) s2 = "null"; //$NON-NLS-1$
+		if (s3 == null) s3 = "null"; //$NON-NLS-1$
+		int l1 = s1.length();
+		int l2 = s2.length();
+		int l3 = s3.length();
+		char[] buf = new char[l1 + l2 + l3];
+		s1.getChars(0, l1, buf, 0);
+		s2.getChars(0, l2, buf, l1);
+		s3.getChars(0, l3, buf, l1 + l2);
+		return new String(buf);
+	}
+	
+	/**
+	 * Converts a type signature from the IBinaryType representation to the DC representation.
+	 */
+	public static String convertTypeSignature(char[] sig) {
+		return new String(sig).replace('/', '.');
+	}
+
+	/**
+	 * Returns true iff str.toLowerCase().endsWith(end.toLowerCase())
+	 * implementation is not creating extra strings.
+	 */
+	public final static boolean endsWithIgnoreCase(String str, String end) {
+		
+		int strLength = str == null ? 0 : str.length();
+		int endLength = end == null ? 0 : end.length();
+		
+		// return false if the string is smaller than the end.
+		if(endLength > strLength)
+			return false;
+			
+		// return false if any character of the end are
+		// not the same in lower case.
+		for(int i = 1 ; i <= endLength; i++){
+			if(Character.toLowerCase(end.charAt(endLength - i)) != Character.toLowerCase(str.charAt(strLength - i)))
+				return false;
+		}
+		
+		return true;
+	}
+
+	/**
+	 * Compares two arrays using equals() on the elements.
+	 * Either or both arrays may be null.
+	 * Returns true if both are null.
+	 * Returns false if only one is null.
+	 * If both are arrays, returns true iff they have the same length and
+	 * all elements are equal.
+	 */
+	public static boolean equalArraysOrNull(int[] a, int[] b) {
+		if (a == b)
+			return true;
+		if (a == null || b == null)
+			return false;
+		int len = a.length;
+		if (len != b.length)
+			return false;
+		for (int i = 0; i < len; ++i) {
+			if (a[i] != b[i])
+				return false;
+		}
+		return true;
+	}
+
+	/**
+	 * Compares two arrays using equals() on the elements.
+	 * Either or both arrays may be null.
+	 * Returns true if both are null.
+	 * Returns false if only one is null.
+	 * If both are arrays, returns true iff they have the same length and
+	 * all elements compare true with equals.
+	 */
+	public static boolean equalArraysOrNull(Object[] a, Object[] b) {
+		if (a == b)	return true;
+		if (a == null || b == null) return false;
+
+		int len = a.length;
+		if (len != b.length) return false;
+		for (int i = 0; i < len; ++i) {
+			if (a[i] == null) {
+				if (b[i] != null) return false;
+			} else {
+				if (!a[i].equals(b[i])) return false;
+			}
+		}
+		return true;
+	}
+	
+	/**
+	 * Compares two String arrays using equals() on the elements.
+	 * The arrays are first sorted.
+	 * Either or both arrays may be null.
+	 * Returns true if both are null.
+	 * Returns false if only one is null.
+	 * If both are arrays, returns true iff they have the same length and
+	 * iff, after sorting both arrays, all elements compare true with equals.
+	 * The original arrays are left untouched.
+	 */
+	public static boolean equalArraysOrNullSortFirst(String[] a, String[] b) {
+		if (a == b)	return true;
+		if (a == null || b == null) return false;
+		int len = a.length;
+		if (len != b.length) return false;
+		if (len >= 2) {  // only need to sort if more than two items
+			a = sortCopy(a);
+			b = sortCopy(b);
+		}
+		for (int i = 0; i < len; ++i) {
+			if (!a[i].equals(b[i])) return false;
+		}
+		return true;
+	}
+	
+	/**
+	 * Compares two arrays using equals() on the elements.
+	 * The arrays are first sorted.
+	 * Either or both arrays may be null.
+	 * Returns true if both are null.
+	 * Returns false if only one is null.
+	 * If both are arrays, returns true iff they have the same length and
+	 * iff, after sorting both arrays, all elements compare true with equals.
+	 * The original arrays are left untouched.
+	 */
+	public static boolean equalArraysOrNullSortFirst(Comparable[] a, Comparable[] b) {
+		if (a == b)	return true;
+		if (a == null || b == null) return false;
+		int len = a.length;
+		if (len != b.length) return false;
+		if (len >= 2) {  // only need to sort if more than two items
+			a = sortCopy(a);
+			b = sortCopy(b);
+		}
+		for (int i = 0; i < len; ++i) {
+			if (!a[i].equals(b[i])) return false;
+		}
+		return true;
+	}
+	
+	/**
+	 * Compares two objects using equals().
+	 * Either or both array may be null.
+	 * Returns true if both are null.
+	 * Returns false if only one is null.
+	 * Otherwise, return the result of comparing with equals().
+	 */
+	public static boolean equalOrNull(Object a, Object b) {
+		if (a == b) {
+			return true;
+		}
+		if (a == null || b == null) {
+			return false;
+		}
+		return a.equals(b);
+	}
+	
+	/**
+	 * Given a qualified name, extract the last component.
+	 * If the input is not qualified, the same string is answered.
+	 */
+	public static String extractLastName(String qualifiedName) {
+		int i = qualifiedName.lastIndexOf('.');
+		if (i == -1) return qualifiedName;
+		return qualifiedName.substring(i+1);
+	}
+	
+	/**
+	 * Extracts the parameter types from a method signature.
+	 */
+	public static String[] extractParameterTypes(char[] sig) {
+		int count = getParameterCount(sig);
+		String[] result = new String[count];
+		if (count == 0)
+			return result;
+		int i = CharOperation.indexOf('(', sig) + 1;
+		count = 0;
+		int len = sig.length;
+		int start = i;
+		for (;;) {
+			if (i == len)
+				break;
+			char c = sig[i];
+			if (c == ')')
+				break;
+			if (c == '[') {
+				++i;
+			} else
+				if (c == 'L') {
+					i = CharOperation.indexOf(';', sig, i + 1) + 1;
+					Assert.isTrue(i != 0);
+					result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
+					start = i;
+				} else {
+					++i;
+					result[count++] = convertTypeSignature(CharOperation.subarray(sig, start, i));
+					start = i;
+				}
+		}
+		return result;
+	}
+
+	/**
+	 * Extracts the return type from a method signature.
+	 */
+	public static String extractReturnType(String sig) {
+		int i = sig.lastIndexOf(')');
+		Assert.isTrue(i != -1);
+		return sig.substring(i+1);	
+	}
+	
+	/**
+	 * Finds the first line separator used by the given text.
+	 *
+	 * @return </code>"\n"</code> or </code>"\r"</code> or  </code>"\r\n"</code>,
+	 *			or <code>null</code> if none found
+	 */
+	public static String findLineSeparator(char[] text) {
+		// find the first line separator
+		int length = text.length;
+		if (length > 0) {
+			char nextChar = text[0];
+			for (int i = 0; i < length; i++) {
+				char currentChar = nextChar;
+				nextChar = i < length-1 ? text[i+1] : ' ';
+				switch (currentChar) {
+					case '\n': return "\n"; //$NON-NLS-1$
+					case '\r': return nextChar == '\n' ? "\r\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$
+				}
+			}
+		}
+		// not found
+		return null;
+	}
+	
+	/**
+	 * Returns the line separator used by the given buffer.
+	 * Uses the given text if none found.
+	 *
+	 * @return </code>"\n"</code> or </code>"\r"</code> or  </code>"\r\n"</code>
+	 */
+	private static String getLineSeparator(char[] text, char[] buffer) {
+		// search in this buffer's contents first
+		String lineSeparator = findLineSeparator(buffer);
+		if (lineSeparator == null) {
+			// search in the given text
+			lineSeparator = findLineSeparator(text);
+			if (lineSeparator == null) {
+				// default to system line separator
+				return System.getProperty("line.separator");
+			}
+		}
+		return lineSeparator;
+	}
+		
+	/**
+	 * Returns the number of parameter types in a method signature.
+	 */
+	public static int getParameterCount(char[] sig) {
+		int i = CharOperation.indexOf('(', sig) + 1;
+		Assert.isTrue(i != 0);
+		int count = 0;
+		int len = sig.length;
+		for (;;) {
+			if (i == len)
+				break;
+			char c = sig[i];
+			if (c == ')')
+				break;
+			if (c == '[') {
+				++i;
+			} else
+				if (c == 'L') {
+					++count;
+					i = CharOperation.indexOf(';', sig, i + 1) + 1;
+					Assert.isTrue(i != 0);
+				} else {
+					++count;
+					++i;
+				}
+		}
+		return count;
+	}
+	
+//	/**
+//	 * Returns the given file's contents as a byte array.
+//	 */
+//	public static byte[] getResourceContentsAsByteArray(IFile file) throws JavaModelException {
+//		InputStream stream= null;
+//		try {
+//			stream = new BufferedInputStream(file.getContents(true));
+//		} catch (CoreException e) {
+//			throw new JavaModelException(e);
+//		}
+//		try {
+//			return org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsByteArray(stream, -1);
+//		} catch (IOException e) {
+//			throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+//		} finally {
+//			try {
+//				stream.close();
+//			} catch (IOException e) {
+//			}
+//		}
+//	}
+//	
+//	/**
+//	 * Returns the given file's contents as a character array.
+//	 */
+//	public static char[] getResourceContentsAsCharArray(IFile file) throws JavaModelException {
+//		String encoding = JavaCore.create(file.getProject()).getOption(JavaCore.CORE_ENCODING, true);
+//		return getResourceContentsAsCharArray(file, encoding);
+//	}
+//
+//	public static char[] getResourceContentsAsCharArray(IFile file, String encoding) throws JavaModelException {
+//		InputStream stream= null;
+//		try {
+//			stream = new BufferedInputStream(file.getContents(true));
+//		} catch (CoreException e) {
+//			throw new JavaModelException(e, IJavaModelStatusConstants.ELEMENT_DOES_NOT_EXIST);
+//		}
+//		try {
+//			return org.eclipse.jdt.internal.compiler.util.Util.getInputStreamAsCharArray(stream, -1, encoding);
+//		} catch (IOException e) {
+//			throw new JavaModelException(e, IJavaModelStatusConstants.IO_EXCEPTION);
+//		} finally {
+//			try {
+//				stream.close();
+//			} catch (IOException e) {
+//			}
+//		}
+//	}
+//	
+//	/**
+//	 * Returns a trimmed version the simples names returned by Signature.
+//	 */
+//	public static String[] getTrimmedSimpleNames(String name) {
+//		String[] result = Signature.getSimpleNames(name);
+//		if (result == null) return null;
+//		for (int i = 0, length = result.length; i < length; i++) {
+//			result[i] = result[i].trim();
+//		}
+//		return result;
+//	}
+	
+	/**
+	 * Returns true iff str.toLowerCase().endsWith(".class")
+	 * implementation is not creating extra strings.
+	 */
+	public final static boolean isClassFileName(String name) {
+		int nameLength = name == null ? 0 : name.length();
+		int suffixLength = SUFFIX_CLASS.length;
+		if (nameLength < suffixLength) return false;
+
+		for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
+			char c = name.charAt(offset + i);
+			if (c != SUFFIX_class[i] && c != SUFFIX_CLASS[i]) return false;
+		}
+		return true;		
+	}
+	
+	/*
+	 * Returns whether the given java element is exluded from its root's classpath.
+	 */
+//	public static final boolean isExcluded(IJavaElement element) {
+//		int elementType = element.getElementType();
+//		switch (elementType) {
+//			case IJavaElement.PACKAGE_FRAGMENT:
+//				PackageFragmentRoot root = (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+//				IResource resource = element.getResource();
+//				return resource != null && Util.isExcluded(resource, root.fullExclusionPatternChars());
+//			case IJavaElement.COMPILATION_UNIT:
+//				root = (PackageFragmentRoot)element.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
+//				resource = element.getResource();
+//				if (resource != null && Util.isExcluded(resource, root.fullExclusionPatternChars()))
+//					return true;
+//				return isExcluded(element.getParent());
+//			default:
+//				IJavaElement cu = element.getAncestor(IJavaElement.COMPILATION_UNIT);
+//				return cu != null && isExcluded(cu);
+//		}
+//	}
+	/*
+	 * Returns whether the given resource path matches one of the exclusion
+	 * patterns.
+	 * 
+	 * @see IClasspathEntry#getExclusionPatterns
+	 */
+	public final static boolean isExcluded(IPath resourcePath, char[][] exclusionPatterns) {
+		if (exclusionPatterns == null) return false;
+		char[] path = resourcePath.toString().toCharArray();
+		for (int i = 0, length = exclusionPatterns.length; i < length; i++)
+			if (CharOperation.pathMatch(exclusionPatterns[i], path, true, '/'))
+				return true;
+		return false;
+	}	
+	
+	/*
+	 * Returns whether the given resource matches one of the exclusion patterns.
+	 * 
+	 * @see IClasspathEntry#getExclusionPatterns
+	 */
+	public final static boolean isExcluded(IResource resource, char[][] exclusionPatterns) {
+		IPath path = resource.getFullPath();
+		// ensure that folders are only excluded if all of their children are excluded
+		if (resource.getType() == IResource.FOLDER)
+			path = path.append("*"); //$NON-NLS-1$
+		return isExcluded(path, exclusionPatterns);
+	}
+
+	/**
+	 * Returns true iff str.toLowerCase().endsWith(".jar" or ".zip")
+	 * implementation is not creating extra strings.
+	 */
+	public final static boolean isArchiveFileName(String name) {
+		int nameLength = name == null ? 0 : name.length();
+		int suffixLength = SUFFIX_JAR.length;
+		if (nameLength < suffixLength) return false;
+
+		int i, offset;
+		for ( i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
+			char c = name.charAt(offset + i);
+			if (c != SUFFIX_jar[i] && c != SUFFIX_JAR[i]) break;
+		}
+		if (i == suffixLength) return true;		
+		for ( i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
+			char c = name.charAt(offset + i);
+			if (c != SUFFIX_zip[i] && c != SUFFIX_ZIP[i]) return false;
+		}
+		return true;
+	}
+	
+	/**
+	 * Validate the given compilation unit name.
+	 * A compilation unit name must obey the following rules:
+	 * <ul>
+	 * <li> it must not be null
+	 * <li> it must include the <code>".java"</code> suffix
+	 * <li> its prefix must be a valid identifier
+	 * </ul>
+	 * </p>
+	 * @param name the name of a compilation unit
+	 * @return a status object with code <code>IStatus.OK</code> if
+	 *		the given name is valid as a compilation unit name, otherwise a status 
+	 *		object indicating what is wrong with the name
+	 */
+//	public static boolean isValidCompilationUnitName(String name) {
+//		return JavaConventions.validateCompilationUnitName(name).getSeverity() != IStatus.ERROR;
+//	}
+
+	/**
+	 * Validate the given .class file name.
+	 * A .class file name must obey the following rules:
+	 * <ul>
+	 * <li> it must not be null
+	 * <li> it must include the <code>".class"</code> suffix
+	 * <li> its prefix must be a valid identifier
+	 * </ul>
+	 * </p>
+	 * @param name the name of a .class file
+	 * @return a status object with code <code>IStatus.OK</code> if
+	 *		the given name is valid as a .class file name, otherwise a status 
+	 *		object indicating what is wrong with the name
+	 */
+//	public static boolean isValidClassFileName(String name) {
+//		return JavaConventions.validateClassFileName(name).getSeverity() != IStatus.ERROR;
+//	}
+
+	/**
+	 * Returns true iff str.toLowerCase().endsWith(".java")
+	 * implementation is not creating extra strings.
+	 */
+	public final static boolean isJavaFileName(String name) {
+		int nameLength = name == null ? 0 : name.length();
+		int suffixLength = SUFFIX_JAVA.length;
+		if (nameLength < suffixLength) return false;
+
+		for (int i = 0, offset = nameLength - suffixLength; i < suffixLength; i++) {
+			char c = name.charAt(offset + i);
+			if (c != SUFFIX_java[i] && c != SUFFIX_JAVA[i]) return false;
+		}
+		return true;		
+	}
+
+	/**
+	 * Returns true if the given method signature is valid,
+	 * false if it is not.
+	 */
+	public static boolean isValidMethodSignature(String sig) {
+		int len = sig.length();
+		if (len == 0) return false;
+		int i = 0;
+		char c = sig.charAt(i++);
+		if (c != '(') return false;
+		if (i >= len) return false;
+		while (sig.charAt(i) != ')') {
+			// Void is not allowed as a parameter type.
+			i = checkTypeSignature(sig, i, len, false);
+			if (i == -1) return false;
+			if (i >= len) return false;
+		}
+		++i;
+		i = checkTypeSignature(sig, i, len, true);
+		return i == len;
+	}
+	
+	/**
+	 * Returns true if the given type signature is valid,
+	 * false if it is not.
+	 */
+	public static boolean isValidTypeSignature(String sig, boolean allowVoid) {
+		int len = sig.length();
+		return checkTypeSignature(sig, 0, len, allowVoid) == len;
+	}
+	
+	/**
+	 * Returns true if the given folder name is valid for a package,
+	 * false if it is not.
+	 */
+//	public static boolean isValidFolderNameForPackage(String folderName) {
+//		return JavaConventions.validateIdentifier(folderName).getSeverity() != IStatus.ERROR;
+//	}	
+
+	/*
+	 * Add a log entry
+	 */
+	public static void log(Throwable e, String message) {
+		Throwable nestedException;
+		if (e instanceof JavaModelException 
+				&& (nestedException = ((JavaModelException)e).getException()) != null) {
+			e = nestedException;
+		}
+		IStatus status= new Status(
+			IStatus.ERROR, 
+			PHPCore.getPlugin().getDescriptor().getUniqueIdentifier(), 
+			IStatus.ERROR, 
+			message, 
+			e); 
+		PHPCore.getPlugin().getLog().log(status);
+	}	
+	
+	/**
+	 * Normalizes the cariage returns in the given text.
+	 * They are all changed  to use the given buffer's line separator.
+	 */
+	public static char[] normalizeCRs(char[] text, char[] buffer) {
+		CharArrayBuffer result = new CharArrayBuffer();
+		int lineStart = 0;
+		int length = text.length;
+		if (length == 0) return text;
+		String lineSeparator = getLineSeparator(text, buffer);
+		char nextChar = text[0];
+		for (int i = 0; i < length; i++) {
+			char currentChar = nextChar;
+			nextChar = i < length-1 ? text[i+1] : ' ';
+			switch (currentChar) {
+				case '\n':
+					int lineLength = i-lineStart;
+					char[] line = new char[lineLength];
+					System.arraycopy(text, lineStart, line, 0, lineLength);
+					result.append(line);
+					result.append(lineSeparator);
+					lineStart = i+1;
+					break;
+				case '\r':
+					lineLength = i-lineStart;
+					if (lineLength >= 0) {
+						line = new char[lineLength];
+						System.arraycopy(text, lineStart, line, 0, lineLength);
+						result.append(line);
+						result.append(lineSeparator);
+						if (nextChar == '\n') {
+							nextChar = ' ';
+							lineStart = i+2;
+						} else {
+							// when line separator are mixed in the same file
+							// \r might not be followed by a \n. If not, we should increment
+							// lineStart by one and not by two.
+							lineStart = i+1;
+						}
+					} else {
+						// when line separator are mixed in the same file
+						// we need to prevent NegativeArraySizeException
+						lineStart = i+1;
+					}
+					break;
+			}
+		}
+		char[] lastLine;
+		if (lineStart > 0) {
+			int lastLineLength = length-lineStart;
+			if (lastLineLength > 0) {
+				lastLine = new char[lastLineLength];
+				System.arraycopy(text, lineStart, lastLine, 0, lastLineLength);
+				result.append(lastLine);
+			}
+			return result.getContents();
+		} else {
+			return text;
+		}
+	}
+
+	/**
+	 * Normalizes the cariage returns in the given text.
+	 * They are all changed  to use given buffer's line sepatator.
+	 */
+	public static String normalizeCRs(String text, String buffer) {
+		return new String(normalizeCRs(text.toCharArray(), buffer.toCharArray()));
+	}
+
+	/**
+	 * Sort the objects in the given collection using the given sort order.
+	 */
+	private static void quickSort(Object[] sortedCollection, int left, int right, int[] sortOrder) {
+		int original_left = left;
+		int original_right = right;
+		int mid = sortOrder[ (left + right) / 2];
+		do {
+			while (sortOrder[left] < mid) {
+				left++;
+			}
+			while (mid < sortOrder[right]) {
+				right--;
+			}
+			if (left <= right) {
+				Object tmp = sortedCollection[left];
+				sortedCollection[left] = sortedCollection[right];
+				sortedCollection[right] = tmp;
+				int tmp2 = sortOrder[left];
+				sortOrder[left] = sortOrder[right];
+				sortOrder[right] = tmp2;
+				left++;
+				right--;
+			}
+		} while (left <= right);
+		if (original_left < right) {
+			quickSort(sortedCollection, original_left, right, sortOrder);
+		}
+		if (left < original_right) {
+			quickSort(sortedCollection, left, original_right, sortOrder);
+		}
+	}
+
+	/**
+	 * Sort the objects in the given collection using the given comparer.
+	 */
+	private static void quickSort(Object[] sortedCollection, int left, int right, Comparer comparer) {
+		int original_left = left;
+		int original_right = right;
+		Object mid = sortedCollection[ (left + right) / 2];
+		do {
+			while (comparer.compare(sortedCollection[left], mid) < 0) {
+				left++;
+			}
+			while (comparer.compare(mid, sortedCollection[right]) < 0) {
+				right--;
+			}
+			if (left <= right) {
+				Object tmp = sortedCollection[left];
+				sortedCollection[left] = sortedCollection[right];
+				sortedCollection[right] = tmp;
+				left++;
+				right--;
+			}
+		} while (left <= right);
+		if (original_left < right) {
+			quickSort(sortedCollection, original_left, right, comparer);
+		}
+		if (left < original_right) {
+			quickSort(sortedCollection, left, original_right, comparer);
+		}
+	}
+
+	/**
+	 * Sort the strings in the given collection.
+	 */
+	private static void quickSort(String[] sortedCollection, int left, int right) {
+		int original_left = left;
+		int original_right = right;
+		String mid = sortedCollection[ (left + right) / 2];
+		do {
+			while (sortedCollection[left].compareTo(mid) < 0) {
+				left++;
+			}
+			while (mid.compareTo(sortedCollection[right]) < 0) {
+				right--;
+			}
+			if (left <= right) {
+				String tmp = sortedCollection[left];
+				sortedCollection[left] = sortedCollection[right];
+				sortedCollection[right] = tmp;
+				left++;
+				right--;
+			}
+		} while (left <= right);
+		if (original_left < right) {
+			quickSort(sortedCollection, original_left, right);
+		}
+		if (left < original_right) {
+			quickSort(sortedCollection, left, original_right);
+		}
+	}
+
+	/**
+	 * Converts the given relative path into a package name.
+	 * Returns null if the path is not a valid package name.
+	 */
+//	public static String packageName(IPath pkgPath) {
+//		StringBuffer pkgName = new StringBuffer(IPackageFragment.DEFAULT_PACKAGE_NAME);
+//		for (int j = 0, max = pkgPath.segmentCount(); j < max; j++) {
+//			String segment = pkgPath.segment(j);
+//			if (!isValidFolderNameForPackage(segment)) {
+//				return null;
+//			}
+//			pkgName.append(segment);
+//			if (j < pkgPath.segmentCount() - 1) {
+//				pkgName.append("." ); //$NON-NLS-1$
+//			}
+//		}
+//		return pkgName.toString();
+//	}
+
+	/**
+	 * Sort the comparable objects in the given collection.
+	 */
+	private static void quickSort(Comparable[] sortedCollection, int left, int right) {
+		int original_left = left;
+		int original_right = right;
+		Comparable mid = sortedCollection[ (left + right) / 2];
+		do {
+			while (sortedCollection[left].compareTo(mid) < 0) {
+				left++;
+			}
+			while (mid.compareTo(sortedCollection[right]) < 0) {
+				right--;
+			}
+			if (left <= right) {
+				Comparable tmp = sortedCollection[left];
+				sortedCollection[left] = sortedCollection[right];
+				sortedCollection[right] = tmp;
+				left++;
+				right--;
+			}
+		} while (left <= right);
+		if (original_left < right) {
+			quickSort(sortedCollection, original_left, right);
+		}
+		if (left < original_right) {
+			quickSort(sortedCollection, left, original_right);
+		}
+	}
+
+	/**
+	 * Sort the strings in the given collection in reverse alphabetical order.
+	 */
+	private static void quickSortReverse(String[] sortedCollection, int left, int right) {
+		int original_left = left;
+		int original_right = right;
+		String mid = sortedCollection[ (left + right) / 2];
+		do {
+			while (sortedCollection[left].compareTo(mid) > 0) {
+				left++;
+			}
+			while (mid.compareTo(sortedCollection[right]) > 0) {
+				right--;
+			}
+			if (left <= right) {
+				String tmp = sortedCollection[left];
+				sortedCollection[left] = sortedCollection[right];
+				sortedCollection[right] = tmp;
+				left++;
+				right--;
+			}
+		} while (left <= right);
+		if (original_left < right) {
+			quickSortReverse(sortedCollection, original_left, right);
+		}
+		if (left < original_right) {
+			quickSortReverse(sortedCollection, left, original_right);
+		}
+	}
+
+	/**
+	 * Sorts an array of objects in place, using the sort order given for each item.
+	 */
+	public static void sort(Object[] objects, int[] sortOrder) {
+		if (objects.length > 1)
+			quickSort(objects, 0, objects.length - 1, sortOrder);
+	}
+
+	/**
+	 * Sorts an array of objects in place.
+	 * The given comparer compares pairs of items.
+	 */
+	public static void sort(Object[] objects, Comparer comparer) {
+		if (objects.length > 1)
+			quickSort(objects, 0, objects.length - 1, comparer);
+	}
+
+	/**
+	 * Sorts an array of strings in place using quicksort.
+	 */
+	public static void sort(String[] strings) {
+		if (strings.length > 1)
+			quickSort(strings, 0, strings.length - 1);
+	}
+
+	/**
+	 * Sorts an array of Comparable objects in place.
+	 */
+	public static void sort(Comparable[] objects) {
+		if (objects.length > 1)
+			quickSort(objects, 0, objects.length - 1);
+	}
+
+	/**
+	 * Sorts an array of Strings, returning a new array
+	 * with the sorted items.  The original array is left untouched.
+	 */
+	public static Object[] sortCopy(Object[] objects, Comparer comparer) {
+		int len = objects.length;
+		Object[] copy = new Object[len];
+		System.arraycopy(objects, 0, copy, 0, len);
+		sort(copy, comparer);
+		return copy;
+	}
+
+	/**
+	 * Sorts an array of Strings, returning a new array
+	 * with the sorted items.  The original array is left untouched.
+	 */
+	public static String[] sortCopy(String[] objects) {
+		int len = objects.length;
+		String[] copy = new String[len];
+		System.arraycopy(objects, 0, copy, 0, len);
+		sort(copy);
+		return copy;
+	}
+
+	/**
+	 * Sorts an array of Comparable objects, returning a new array
+	 * with the sorted items.  The original array is left untouched.
+	 */
+	public static Comparable[] sortCopy(Comparable[] objects) {
+		int len = objects.length;
+		Comparable[] copy = new Comparable[len];
+		System.arraycopy(objects, 0, copy, 0, len);
+		sort(copy);
+		return copy;
+	}
+
+	/**
+	 * Sorts an array of strings in place using quicksort
+	 * in reverse alphabetical order.
+	 */
+	public static void sortReverseOrder(String[] strings) {
+		if (strings.length > 1)
+			quickSortReverse(strings, 0, strings.length - 1);
+	}
+
+	/**
+	 * Converts a String[] to char[][].
+	 */
+	public static char[][] toCharArrays(String[] a) {
+		int len = a.length;
+		char[][] result = new char[len][];
+		for (int i = 0; i < len; ++i) {
+			result[i] = toChars(a[i]);
+		}
+		return result;
+	}
+
+	/**
+	 * Converts a String to char[].
+	 */
+	public static char[] toChars(String s) {
+		int len = s.length();
+		char[] chars = new char[len];
+		s.getChars(0, len, chars, 0);
+		return chars;
+	}
+
+	/**
+	 * Converts a String to char[][], where segments are separate by '.'.
+	 */
+	public static char[][] toCompoundChars(String s) {
+		int len = s.length();
+		if (len == 0) {
+			return CharOperation.NO_CHAR_CHAR;
+		}
+		int segCount = 1;
+		for (int off = s.indexOf('.'); off != -1; off = s.indexOf('.', off + 1)) {
+			++segCount;
+		}
+		char[][] segs = new char[segCount][];
+		int start = 0;
+		for (int i = 0; i < segCount; ++i) {
+			int dot = s.indexOf('.', start);
+			int end = (dot == -1 ? s.length() : dot);
+			segs[i] = new char[end - start];
+			s.getChars(start, end, segs[i], 0);
+			start = end + 1;
+		}
+		return segs;
+	}
+
+	/**
+	 * Converts a char[][] to String, where segments are separated by '.'.
+	 */
+	public static String toString(char[][] c) {
+		StringBuffer sb = new StringBuffer();
+		for (int i = 0, max = c.length; i < max; ++i) {
+			if (i != 0) sb.append('.');
+			sb.append(c[i]);
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * Converts a char[][] and a char[] to String, where segments are separated by '.'.
+	 */
+	public static String toString(char[][] c, char[] d) {
+		if (c == null) return new String(d);
+		StringBuffer sb = new StringBuffer();
+		for (int i = 0, max = c.length; i < max; ++i) {
+			sb.append(c[i]);
+			sb.append('.');
+		}
+		sb.append(d);
+		return sb.toString();
+	}
+
+	/**
+	 * Converts a char[] to String.
+	 */
+	public static String toString(char[] c) {
+		return new String(c);
+	}
+
+	/**
+	 * Converts an array of Objects into String.
+	 */
+	public static String toString(Object[] objects) {
+		return toString(objects, 
+			new Displayable(){ 
+				public String displayString(Object o) { 
+					if (o == null) return "null"; //$NON-NLS-1$
+					return o.toString(); 
+				}
+			});
+	}
+
+	/**
+	 * Converts an array of Objects into String.
+	 */
+	public static String toString(Object[] objects, Displayable renderer) {
+		if (objects == null) return ""; //$NON-NLS-1$
+		StringBuffer buffer = new StringBuffer(10);
+		for (int i = 0; i < objects.length; i++){
+			if (i > 0) buffer.append(", "); //$NON-NLS-1$
+			buffer.append(renderer.displayString(objects[i]));
+		}
+		return buffer.toString();
+	}
+	
+	/**
+	 * Asserts that the given method signature is valid.
+	 */
+	public static void validateMethodSignature(String sig) {
+		Assert.isTrue(isValidMethodSignature(sig));
+	}
+
+	/**
+	 * Asserts that the given type signature is valid.
+	 */
+	public static void validateTypeSignature(String sig, boolean allowVoid) {
+		Assert.isTrue(isValidTypeSignature(sig, allowVoid));
+	}
+
+	/**
+	 * Creates a NLS catalog for the given locale.
+	 */
+	public static void relocalize() {
+		try {
+			bundle = ResourceBundle.getBundle(bundleName, Locale.getDefault());
+		} catch(MissingResourceException e) {
+			System.out.println("Missing resource : " + bundleName.replace('.', '/') + ".properties for locale " + Locale.getDefault()); //$NON-NLS-1$//$NON-NLS-2$
+			throw e;
+		}
+	}
+	
+	/**
+	 * Put all the arguments in one String.
+	 */
+	public static String getProblemArgumentsForMarker(String[] arguments){
+		StringBuffer args = new StringBuffer(10);
+		
+		args.append(arguments.length);
+		args.append(':');
+		
+			
+		for (int j = 0; j < arguments.length; j++) {
+			if(j != 0)
+				args.append(ARGUMENTS_DELIMITER);
+			
+			if(arguments[j].length() == 0) {
+				args.append(EMPTY_ARGUMENT);
+			} else {			
+				args.append(arguments[j]);
+			}
+		}
+		
+		return args.toString();
+	}
+	
+	/**
+	 * Separate all the arguments of a String made by getProblemArgumentsForMarker
+	 */
+	public static String[] getProblemArgumentsFromMarker(String argumentsString){
+		if (argumentsString == null) return null;
+		int index = argumentsString.indexOf(':');
+		if(index == -1)
+			return null;
+		
+		int length = argumentsString.length();
+		int numberOfArg;
+		try{
+			numberOfArg = Integer.parseInt(argumentsString.substring(0 , index));
+		} catch (NumberFormatException e) {
+			return null;
+		}
+		argumentsString = argumentsString.substring(index + 1, length);
+		
+		String[] args = new String[length];
+		int count = 0;
+		
+		StringTokenizer tokenizer = new StringTokenizer(argumentsString, ARGUMENTS_DELIMITER);
+		while(tokenizer.hasMoreTokens()) {
+			String argument = tokenizer.nextToken();
+			if(argument.equals(EMPTY_ARGUMENT))
+				argument = "";  //$NON-NLS-1$
+			args[count++] = argument;
+		}
+		
+		if(count != numberOfArg)
+			return null;
+		
+		System.arraycopy(args, 0, args = new String[count], 0, count);
+		return args;
+	}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/CharArrayBuffer.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/CharArrayBuffer.java
new file mode 100644
index 0000000..38be3f8
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/core/util/CharArrayBuffer.java
@@ -0,0 +1,191 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.core.util;
+
+/**
+ * The <code>CharArrayBuffer</code> is intended as a lightweight partial implementation
+ * of the StringBuffer class, but using <code>char[]'s</code> instead of Strings.
+ *
+ * <p>The <code>CharArrayBuffer</code> maintains a list of <code>char[]'s</code>
+ * which don't get appended until the user asks for them.  The following
+ * code illustrates how to use the class.
+ *
+ * <code>
+ * CharArrayBuffer buffer = new CharArrayBuffer(myCharArray);
+ * buffer.append(moreBytes, 0, someLength);
+ * myCharArray = buffer.getContents();
+ * </code>
+ *
+ * <p>NOTE: This class is not Thread safe!
+ */
+public class CharArrayBuffer {
+	/**
+	 * This is the buffer of char arrays which must be appended together
+	 * during the getContents method.
+	 */
+	protected char[][] fBuffer;
+
+	/**
+	 * The default buffer size.
+	 */
+	public static final int DEFAULT_BUFFER_SIZE = 10;
+
+	/**
+	 * The end of the buffer
+	 */
+	protected int fEnd;
+
+	/**
+	 * The current size of the buffer.
+	 */
+	protected int fSize;
+
+	/**
+	 * A buffer of ranges which is maintained along with
+	 * the buffer.  Ranges are of the form {start, length}.
+	 * Enables append(char[] array, int start, int end).
+	 */
+	protected int[][] fRanges;
+/**
+ * Creates a <code>CharArrayBuffer</code> with the default buffer size (10).
+ */
+public CharArrayBuffer() {
+	this(null, DEFAULT_BUFFER_SIZE);
+}
+/**
+ * Creates a <code>CharArrayBuffer</code> with the default buffer size,
+ * and sets the first element in the buffer to be the given char[].
+ *
+ * @param first - the first element to be placed in the buffer, ignored if null
+ */
+public CharArrayBuffer(char[] first) {
+	this(first, DEFAULT_BUFFER_SIZE);
+}
+/**
+ * Creates a <code>CharArrayBuffer</code> with the given buffer size,
+ * and sets the first element in the buffer to be the given char array.
+ *
+ * @param first - the first element of the buffer, ignored if null.
+ * @param size - the buffer size, if less than 1, set to the DEFAULT_BUFFER_SIZE.
+ */
+public CharArrayBuffer(char[] first, int size) {
+	fSize = (size > 0) ? size : DEFAULT_BUFFER_SIZE;
+	fBuffer = new char[fSize][];
+	fRanges = new int[fSize][];
+	fEnd = 0;
+	if (first != null)
+		append(first, 0, first.length);
+}
+/**
+ * Creates a <code>CharArrayBuffer</code> with the given buffer size.
+ *
+ * @param size - the size of the buffer.
+ */
+public CharArrayBuffer(int size) {
+	this(null, size);
+}
+/**
+ * Appends the entire given char array.  Given for convenience.
+ *
+ * @param src - a char array which is appended to the end of the buffer.
+ */
+public CharArrayBuffer append(char[] src) {
+	if (src != null)
+		append(src, 0, src.length);
+	return this;
+}
+/**
+ * Appends a sub array of the given array to the buffer.
+ *
+ * @param src - the next array of characters to be appended to the buffer, ignored if null
+ * @param start - the start index in the src array.
+ * @param length - the number of characters from start to be appended
+ *
+ * @throws ArrayIndexOutOfBoundsException - if arguments specify an array index out of bounds.
+ */
+public CharArrayBuffer append(char[] src, int start, int length) {
+	if (start < 0) throw new ArrayIndexOutOfBoundsException();
+	if (length < 0) throw new ArrayIndexOutOfBoundsException();
+	if (src != null) {
+		int srcLength = src.length;
+		if (start > srcLength) throw new ArrayIndexOutOfBoundsException();
+		if (length + start > srcLength) throw new ArrayIndexOutOfBoundsException();
+		/** do length check here to allow exceptions to be thrown */
+		if (length > 0) {
+			if (fEnd == fSize) {
+				int size2 = fSize * 2;
+				System.arraycopy(fBuffer, 0, (fBuffer = new char[size2][]), 0, fSize);
+				System.arraycopy(fRanges, 0, (fRanges = new int[size2][]), 0, fSize);
+				fSize *= 2;
+			}
+			fBuffer[fEnd] = src;
+			fRanges[fEnd] = new int[] {start, length};
+			fEnd++;
+		}
+	}
+	return this;
+}
+/**
+ * Appends the given char.  Given for convenience.
+ *
+ * @param src - a char which is appended to the end of the buffer.
+ */
+public CharArrayBuffer append(char c) {
+	append(new char[] {c}, 0, 1);
+	return this;
+}
+/**
+ * Appends the given String to the buffer.  Given for convenience, use
+ * #append(char[]) if possible
+ *
+ * @param src - a char array which is appended to the end of the buffer.
+ */
+public CharArrayBuffer append(String src) {
+	if (src != null)
+		append(src.toCharArray(), 0, src.length());
+	return this;
+}
+/**
+ * Returns the entire contents of the buffer as one
+ * char[] or null if nothing has been put in the buffer.
+ */
+public char[] getContents() {
+	if (fEnd == 0)
+		return null;
+
+	// determine the size of the array
+	int size = 0;
+	for (int i = 0; i < fEnd; i++)
+		size += fRanges[i][1];
+
+	if (size > 0) {
+		char[] result = new char[size];
+		int current = 0;
+		// copy the results
+		for(int i = 0; i < fEnd; i++) {
+			int[] range = fRanges[i];
+			int length = range[1];
+			System.arraycopy(fBuffer[i], range[0], result, current, length);
+			current += length;
+		}
+		return result;
+	}
+	return null;
+}
+/**
+ * Returns the contents of the buffer as a String, or
+ * <code>null</code> if the buffer is empty.
+ */
+public String toString() {
+	char[] contents = getContents();
+	return (contents != null) ? new String(contents) : null;
+}
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/PHPDocCommentReader.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/PHPDocCommentReader.java
new file mode 100644
index 0000000..7b1f275
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/PHPDocCommentReader.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package net.sourceforge.phpdt.internal.corext.phpdoc;
+
+import net.sourceforge.phpdt.core.IBuffer;
+import net.sourceforge.phpdt.internal.corext.util.Strings;
+
+
+/**
+ * Reads a java doc comment from a java doc comment. Skips star-character
+ * on begin of line
+ */
+public class PHPDocCommentReader extends SingleCharReader {
+
+	private IBuffer fBuffer;
+	
+	private int fCurrPos;
+	private int fStartPos;
+	private int fEndPos;
+	
+	private boolean fWasNewLine;
+		
+	public PHPDocCommentReader(IBuffer buf, int start, int end) {
+		fBuffer= buf;
+		fStartPos= start + 3;
+		fEndPos= end - 2;
+		
+		reset();
+	}
+		
+	/**
+	 * @see java.io.Reader#read()
+	 */
+	public int read() {
+		if (fCurrPos < fEndPos) {
+			char ch;
+			if (fWasNewLine) {
+				do {
+					ch= fBuffer.getChar(fCurrPos++);
+				} while (fCurrPos < fEndPos && Character.isWhitespace(ch));
+				if (ch == '*') {
+					if (fCurrPos < fEndPos) {
+						do {
+							ch= fBuffer.getChar(fCurrPos++);
+						} while (ch == '*');
+					} else {
+						return -1;
+					}
+				}
+			} else {
+				ch= fBuffer.getChar(fCurrPos++);
+			}
+			fWasNewLine= Strings.isLineDelimiterChar(ch);
+			
+			return ch;
+		}
+		return -1;
+	}
+		
+	/**
+	 * @see java.io.Reader#close()
+	 */		
+	public void close() {
+		fBuffer= null;
+	}
+	
+	/**
+	 * @see java.io.Reader#reset()
+	 */		
+	public void reset() {
+		fCurrPos= fStartPos;
+		fWasNewLine= true;
+	}	
+		
+		
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/SingleCharReader.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/SingleCharReader.java
index 2507032..87340b4 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/SingleCharReader.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/phpdoc/SingleCharReader.java
@@ -1,9 +1,15 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
 package net.sourceforge.phpdt.internal.corext.phpdoc;
 
-/*
- * (c) Copyright IBM Corp. 2000, 2001.
- * All Rights Reserved.
- */
 
 import java.io.IOException;
 import java.io.Reader;
@@ -52,4 +58,4 @@ public abstract class SingleCharReader extends Reader {
 		}
 		return buf.toString();
 	}
-}
\ No newline at end of file
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/util/Strings.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/util/Strings.java
deleted file mode 100644
index ab80732..0000000
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/corext/util/Strings.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * (c) Copyright IBM Corp. 2000, 2001.
- * All Rights Reserved.
- */
-package net.sourceforge.phpdt.internal.corext.util;
-
-import org.eclipse.jface.text.BadLocationException;
-import org.eclipse.jface.text.DefaultLineTracker;
-import org.eclipse.jface.text.ILineTracker;
-import org.eclipse.jface.text.IRegion;
-
-//import org.eclipse.jdt.internal.corext.Assert;
-
-/**
- * Helper class to provide String manipulation functions not available in standard JDK.
- */
-public class Strings {
-
-	public static String removeNewLine(String message) {
-		StringBuffer result= new StringBuffer();
-		int current= 0;
-		int index= message.indexOf('\n', 0);
-		while (index != -1) {
-			result.append(message.substring(current, index));
-			if (current < index && index != 0)
-				result.append(' ');
-			current= index + 1;
-			index= message.indexOf('\n', current);
-		}
-		result.append(message.substring(current));
-		return result.toString();
-	}
-
-	/**
-	 * Converts the given string into an array of lines. The lines 
-	 * don't contain any line delimiter characters.
-	 *
-	 * @return the string converted into an array of strings. Returns <code>
-	 * 	null</code> if the input string can't be converted in an array of lines.
-	 */
-	public static String[] convertIntoLines(String input) {
-		try {
-			ILineTracker tracker= new DefaultLineTracker();
-			tracker.set(input);
-			int size= tracker.getNumberOfLines();
-			String result[]= new String[size];
-			for (int i= 0; i < size; i++) {
-				IRegion region= tracker.getLineInformation(i);
-				int offset= region.getOffset();
-				result[i]= input.substring(offset, offset + region.getLength());
-			}
-			return result;
-		} catch (BadLocationException e) {
-			return null;
-		}
-	}
-
-	/**
-	 * Returns <code>true</code> if the given string only consists of
-	 * white spaces according to Java. If the string is empty, <code>true
-	 * </code> is returned.
-	 * 
-	 * @return <code>true</code> if the string only consists of white
-	 * 	spaces; otherwise <code>false</code> is returned
-	 * 
-	 * @see java.lang.Character#isWhitespace(char)
-	 */
-	public static boolean containsOnlyWhitespaces(String s) {
-		int size= s.length();
-		for (int i= 0; i < size; i++) {
-			if (!Character.isWhitespace(s.charAt(i)))
-				return false;
-		}
-		return true;
-	}
-	
-	/**
-	 * Removes leading tabs and spaces from the given string. If the string
-	 * doesn't contain any leading tabs or spaces then the string itself is 
-	 * returned.
-	 */
-	public static String trimLeadingTabsAndSpaces(String line) {
-		int size= line.length();
-		int start= size;
-		for (int i= 0; i < size; i++) {
-			char c= line.charAt(i);
-			if (c != '\t' && !Character.isSpaceChar(c)) {
-				start= i;
-				break;
-			}
-		}
-		if (start == 0)
-			return line;
-		else if (start == size)
-			return ""; //$NON-NLS-1$
-		else
-			return line.substring(start);
-	}
-	
-	public static String trimTrailingTabsAndSpaces(String line) {
-		int size= line.length();
-		int end= size;
-		for (int i= size - 1; i >= 0; i--) {
-			char c= line.charAt(i);
-			if (c == '\t' || Character.isSpaceChar(c)) {
-				end= i;
-			} else {
-				break;
-			}
-		}
-		if (end == size)
-			return line;
-		else if (end == 0)
-			return ""; //$NON-NLS-1$
-		else
-			return line.substring(0, end);
-	}
-	
-	/**
-	 * Returns the indent of the given string.
-	 * 
-	 * @param line the text line
-	 * @param tabWidth the width of the '\t' character.
-	 */
-	public static int computeIndent(String line, int tabWidth) {
-		int result= 0;
-		int blanks= 0;
-		int size= line.length();
-		for (int i= 0; i < size; i++) {
-			char c= line.charAt(i);
-			if (c == '\t') {
-				result++;
-				blanks= 0;
-			} else if (Character.isSpaceChar(c)) {
-				blanks++;
-				if (blanks == tabWidth) {
-					result++;
-					blanks= 0;
-				}
-			} else {
-				return result;
-			}
-		}
-		return result;
-	}
-	
-	/**
-	 * Removes the given number of idents from the line. Asserts that the given line 
-	 * has the requested number of indents. If <code>indentsToRemove <= 0</code>
-	 * the line is returned.
-	 */
-	public static String trimIndent(String line, int indentsToRemove, int tabWidth) {
-		if (line == null || indentsToRemove <= 0)
-			return line;
-			
-		int start= 0;
-		int indents= 0;
-		int blanks= 0;
-		int size= line.length();
-		for (int i= 0; i < size; i++) {
-			char c= line.charAt(i);
-			if (c == '\t') {
-				indents++;
-				blanks= 0;
-			} else if (Character.isSpaceChar(c)) {
-					blanks++;
-					if (blanks == tabWidth) {
-						indents++;
-						blanks= 0;
-					}
-			} else {
-//				Assert.isTrue(false, "Line does not have requested number of indents"); //$NON-NLS-1$
-			}
-			if (indents == indentsToRemove) {
-				start= i + 1;
-				break;
-			}	
-		}
-		if (start == size)
-			return ""; //$NON-NLS-1$
-		else
-			return line.substring(start);
-	}
-	
-	/**
-	 * Removes all leading indents from the given line. If the line doesn't contain
-	 * any indents the line itself is returned.
-	 */
-	public static String trimIndents(String s, int tabWidth) {
-		int indent= computeIndent(s, tabWidth);
-		if (indent == 0)
-			return s;
-		return trimIndent(s, indent, tabWidth);
-	}
-	
-	/**
-	 * Removes the common number of indents from all lines. If a line
-	 * only consists out of white space it is ignored.
-	 */
-	public static void trimIndentation(String[] lines, int tabWidth) {
-		String[] toDo= new String[lines.length];
-		// find indentation common to all lines
-		int minIndent= Integer.MAX_VALUE; // very large
-		for (int i= 0; i < lines.length; i++) {
-			String line= lines[i];
-			if (containsOnlyWhitespaces(line))
-				continue;
-			toDo[i]= line;
-			int indent= computeIndent(line, tabWidth);
-			if (indent < minIndent) {
-				minIndent= indent;
-			}
-		}
-		
-		if (minIndent > 0) {
-			// remove this indent from all lines
-			for (int i= 0; i < toDo.length; i++) {
-				String s= toDo[i];
-				if (s != null)
-					lines[i]= trimIndent(s, minIndent, tabWidth);
-				else {
-					String line= lines[i];
-					int indent= computeIndent(line, tabWidth);
-					if (indent > minIndent)
-						lines[i]= trimIndent(line, minIndent, tabWidth);
-					else
-						lines[i]= trimLeadingTabsAndSpaces(line);
-				}
-			}
-		}
-	}
-	
-	public static String getIndentString(String line, int tabWidth) {
-		int size= line.length();
-		int end= 0;
-		int blanks= 0;
-		for (int i= 0; i < size; i++) {
-			char c= line.charAt(i);
-			if (c == '\t') {
-				end= i;
-				blanks= 0;
-			} else if (Character.isSpaceChar(c)) {
-				blanks++;
-				if (blanks == tabWidth) {
-					end= i;
-					blanks= 0;
-				}
-			} else {
-				break;
-			}
-		}
-		if (end == 0)
-			return ""; //$NON-NLS-1$
-		else if (end == size)
-			return line;
-		else
-			return line.substring(0, end + 1);
-	}
-}
-
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPElementVisitor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPElementVisitor.java
index da79e24..347ff8c 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPElementVisitor.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPElementVisitor.java
@@ -25,9 +25,7 @@ public class PHPElementVisitor implements IResourceVisitor {
 
 			case IResource.FILE :
 				IFile fileResource = (IFile) resource;
-				if ( "php".equals(fileResource.getFileExtension()) ||
-             "php3".equals(fileResource.getFileExtension()) ||
-             "php4".equals(fileResource.getFileExtension()) ) {
+				if ( PHPFileUtil.isPHPFile(fileResource) ) {
 					phpFiles.add(fileResource);
 					return true;
 				}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPFileUtil.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPFileUtil.java
new file mode 100644
index 0000000..4917de5
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpdt/internal/ui/util/PHPFileUtil.java
@@ -0,0 +1,23 @@
+/*
+ * Created on 09.08.2003
+ *
+ */
+package net.sourceforge.phpdt.internal.ui.util;
+
+import org.eclipse.core.resources.IFile;
+
+/**
+ * @author khartlage
+ *
+ */
+public class PHPFileUtil {
+  static public boolean isPHPFile(IFile file) {
+    if ("php".equalsIgnoreCase(file.getFileExtension())
+      || "php3".equalsIgnoreCase(file.getFileExtension())
+      || "php4".equalsIgnoreCase(file.getFileExtension())
+      || "inc".equalsIgnoreCase(file.getFileExtension())) {
+      return true;
+    }
+    return false;
+  }
+}
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/IPreferenceConstants.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/IPreferenceConstants.java
index 356a860..833cb2b 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/IPreferenceConstants.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/IPreferenceConstants.java
@@ -36,7 +36,7 @@ public interface IPreferenceConstants {
   public static final String PHP_PARSER_DEFAULT = "_php_parser_default";
   public static final String PHP_INTERNAL_PARSER = "_php_internal_parser";
   public static final String PHP_EXTERNAL_PARSER = "_php_external_parser";
-  public static final String PHP_PARSE_ON_SAVE = "_php_parse_on_save";
+  // public static final String PHP_PARSE_ON_SAVE = "_php_parse_on_save";
   public static final String PHP_MULTILINE_COMMENT = "_php_multilineComment";
   public static final String PHP_MULTILINE_COMMENT_BOLD = "_php_multilineComment_bold";
   public static final String PHP_MULTILINE_COMMENT_ITALIC = "_php_multilineComment_italic";
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPEclipseParserPreferencePage.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPEclipseParserPreferencePage.java
index 45b4179..6460f92 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPEclipseParserPreferencePage.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPEclipseParserPreferencePage.java
@@ -30,7 +30,7 @@ public class PHPEclipseParserPreferencePage extends PreferencePage implements IW
 
   RadioGroupFieldEditor chooseParser;
   StringFieldEditor externalParserSFE;
-  BooleanFieldEditor parseOnSave;
+ // BooleanFieldEditor parseOnSave;
 
   public PHPEclipseParserPreferencePage() {
     super();
@@ -42,14 +42,14 @@ public class PHPEclipseParserPreferencePage extends PreferencePage implements IW
   protected void performDefaults() {
     chooseParser.loadDefault();
     externalParserSFE.loadDefault();
-    parseOnSave.loadDefault();
+//    parseOnSave.loadDefault();
     super.performDefaults();
   }
 
   public boolean performOk() {
     chooseParser.store();
     externalParserSFE.store();
-    parseOnSave.store();
+//    parseOnSave.store();
     return super.performOk();
   }
 
@@ -99,14 +99,14 @@ public class PHPEclipseParserPreferencePage extends PreferencePage implements IW
     externalParserSFE.setPreferenceStore(getPreferenceStore());
     externalParserSFE.load();
 
-    parseOnSave =
-      new BooleanFieldEditor(
-        PHPeclipsePlugin.PHP_PARSE_ON_SAVE,
-        PHPPreferencesMessages.getString("PHPBasePreferencePage.parsers.pos"),
-        parserSettingsGroup);
-    parseOnSave.setPreferencePage(this);
-    parseOnSave.setPreferenceStore(getPreferenceStore());
-    parseOnSave.load();
+//    parseOnSave =
+//      new BooleanFieldEditor(
+//        PHPeclipsePlugin.PHP_PARSE_ON_SAVE,
+//        PHPPreferencesMessages.getString("PHPBasePreferencePage.parsers.pos"),
+//        parserSettingsGroup);
+//    parseOnSave.setPreferencePage(this);
+//    parseOnSave.setPreferenceStore(getPreferenceStore());
+//    parseOnSave.load();
 
     return composite;
   }
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java
index 7f027b7..7619c59 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/PHPeclipsePlugin.java
@@ -56,6 +56,13 @@ public class PHPeclipsePlugin extends AbstractUIPlugin implements IPreferenceCon
    */
   public static final String PLUGIN_ID = "net.sourceforge.phpeclipse"; //$NON-NLS-1$
   public final static String PHP_NATURE_ID = PLUGIN_ID + ".phpnature";
+  
+	/** 
+	 * id of builder - matches plugin.xml (concatenate pluginid.builderid) 
+	 */
+	public static final String BUILDER_INDEX_ID =	PLUGIN_ID + ".indexbuilder";
+	public static final String BUILDER_PARSER_ID =	PLUGIN_ID + ".parserbuilder";
+		
   // public static final String PHP_RESOURCES_VIEW_ID = PLUGIN_ID + ".resourcesview.ViewPHPResources"; //$NON-NLS-1$
   public static final String PHP_CODING_ACTION_SET_ID = PLUGIN_ID + ".ui.CodingActionSet"; //$NON-NLS-1$
 
@@ -323,7 +330,7 @@ public class PHPeclipsePlugin extends AbstractUIPlugin implements IPreferenceCon
     store.setDefault(PHP_INTERNAL_PARSER, "false");
     store.setDefault(PHP_EXTERNAL_PARSER, "true");
 
-    store.setDefault(PHP_PARSE_ON_SAVE, "true");
+//    store.setDefault(PHP_PARSE_ON_SAVE, "true");
 
     // show line numbers:
     //   store.setDefault(LINE_NUMBER_RULER, "false");
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/PHPStartApacheAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/PHPStartApacheAction.java
index 5883fbe..f6ab554 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/PHPStartApacheAction.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/actions/PHPStartApacheAction.java
@@ -29,12 +29,14 @@ public class PHPStartApacheAction implements IWorkbenchWindowActionDelegate {
   protected IWorkbenchWindow activeWindow = null;
 
   public void run(IAction action) {
-    final IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
+    final IPreferenceStore store =
+      PHPeclipsePlugin.getDefault().getPreferenceStore();
     String documentRoot = store.getString(PHPeclipsePlugin.DOCUMENTROOT_PREF);
     // replace backslash with slash in the DocumentRoot under Windows
     documentRoot = documentRoot.replace('\\', '/');
     String[] arguments = { documentRoot };
-    MessageFormat form = new MessageFormat(store.getString(PHPeclipsePlugin.APACHE_START_PREF));
+    MessageFormat form =
+      new MessageFormat(store.getString(PHPeclipsePlugin.APACHE_START_PREF));
     execute(
       "apache_start",
       store.getString(PHPeclipsePlugin.APACHE_RUN_PREF),
@@ -77,13 +79,29 @@ public class PHPStartApacheAction implements IWorkbenchWindowActionDelegate {
   	 * @param arguments arguments for this configuration
   	 * @param background run this configuration in background mode
   	 */
-  public static void execute(String command, String executable, String arguments, boolean background) {
+  public static void execute(
+    String command,
+    String executable,
+    String arguments,
+    boolean background) {
     PHPConsole console = PHPConsole.getInstance();
     String consoleMessage;
     if (background) {
-      consoleMessage = "run in background mode-" + command + ": " + executable + " " + arguments;
+      consoleMessage =
+        "run in background mode-"
+          + command
+          + ": "
+          + executable
+          + " "
+          + arguments;
     } else {
-      consoleMessage = "run in foreground mode-" + command + ": " + executable + " " + arguments;
+      consoleMessage =
+        "run in foreground mode-"
+          + command
+          + ": "
+          + executable
+          + " "
+          + arguments;
     }
     console.write(consoleMessage + "\n");
 
@@ -120,9 +138,14 @@ public class PHPStartApacheAction implements IWorkbenchWindowActionDelegate {
   public static String getParserOutput(String command, String consoleMessage) {
     //    MessageDialog.openInformation(activeWindow.getShell(), "Exec command: ", command);
     try {
-      PHPConsole console = PHPConsole.getInstance();
-      if (console != null) {
-        console.write(consoleMessage + command + "\n");
+      PHPConsole console = null;
+      try {
+        console = PHPConsole.getInstance();
+        if (console != null) {
+          console.write(consoleMessage + command + "\n");
+        }
+      } catch (Throwable th) {
+
       }
 
       Runtime runtime = Runtime.getRuntime();
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserBuilder.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserBuilder.java
new file mode 100644
index 0000000..4b9babe
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserBuilder.java
@@ -0,0 +1,159 @@
+package net.sourceforge.phpeclipse.builder;
+
+import java.util.Map;
+
+import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
+import net.sourceforge.phpeclipse.phpeditor.PHPParserAction;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceVisitor;
+import org.eclipse.core.resources.IncrementalProjectBuilder;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+
+/**
+ * Builder for .php files. 
+ * 
+ * 
+ * @see org.eclipse.core.resources.IncrementalProjectBuilder
+ * @see org.eclipse.core.resources.IResourceDelta
+ */
+public class ParserBuilder extends IncrementalProjectBuilder {
+  private final static int TOTAL_WORK = 100;
+
+  /**
+   * Constructor
+   */
+  public ParserBuilder() {
+  }
+
+  /**
+   * 
+   */
+  protected IProject[] build(int kind, Map args, IProgressMonitor monitor)
+    throws CoreException {
+    monitor.beginTask("Parsing files", TOTAL_WORK);
+
+    if (kind == IncrementalProjectBuilder.FULL_BUILD) {
+      IResourceDelta delta = getDelta(getProject());
+
+      processFull(getProject(), monitor);
+
+    } else { // INCREMENTAL_BUILD or AUTO_BUILD
+
+      IResourceDelta delta = getDelta(getProject());
+      if (delta != null) {
+        delta.accept(new ParserVisitor(monitor));
+      }
+
+    }
+    monitor.done();
+    return null;
+  }
+
+  /**
+   * Performs a <code>FULL_BUILD</code> by visiting all nodes in the resource
+   * tree under the specified project.  
+   * 
+   * @param iProject
+   */
+  public void processFull(IProject iProject, final IProgressMonitor monitor) {
+
+    // Create resource visitor logic
+    IResourceVisitor myVisitor = new IResourceVisitor() {
+      public boolean visit(IResource resource) throws CoreException {
+        if (resource.getType() == IResource.FILE) {
+          if (monitor.isCanceled()) {
+            throw new OperationCanceledException();
+          }
+          if ((resource.getFileExtension() != null)
+            && PHPFileUtil.isPHPFile((IFile) resource)) {
+            monitor.worked(1);
+            monitor.subTask("Parsing: " + resource.getFullPath());
+            PHPParserAction.parseFile((IFile) resource);
+          }
+        }
+
+        return true;
+      }
+    };
+
+    // Process the project using the visitor just created
+    try {
+      iProject.accept(myVisitor);
+    } catch (CoreException e) {
+      e.printStackTrace();
+    }
+
+  }
+
+  /** 
+   * Sets initialization data for this builder.
+   * <p>
+   * This method is part of the <code>IExecutableExtension</code>
+   * interface.
+   * </p>
+   * <p>
+   * Subclasses are free to extend this method to pick up 
+   * initialization parameters from the plug-in plug-in manifest 
+   * (<code>plugin.xml</code>) file,
+   * but should be sure to invoke this method on their superclass.
+   * <p>
+   * For example, the following method looks for a boolean-valued 
+   * parameter named "trace":
+   * <pre>
+   *     public void setInitializationData(IConfigurationElement cfig, 
+   *             String propertyName, Object data) 
+   * 		        throws CoreException {
+   *         super.setInitializationData(cfig, propertyName, data);
+   *         if (data instanceof Hashtable) { 
+   *             Hashtable args = (Hashtable) data; 
+   *             String traceValue = (String) args.get("trace"); 
+   *             TRACING = (traceValue!=null && traceValue.equals("true"));
+   *         }
+   *     }
+   * </pre>
+   * </p>
+   */
+  public void setInitializationData(
+    IConfigurationElement config,
+    String propertyName,
+    Object data)
+    throws CoreException {
+    super.setInitializationData(config, propertyName, data);
+
+  }
+
+  /**
+   * Informs this builder that it is being started by the build management
+   * infrastructure.  By the time this method is run, the builder's project
+   * is available and <code>setInitializationData</code> has been called.
+   * The default implementation should be called by all overriding methods.
+   *
+   * @see #setInitializationData
+   */
+  protected void startupOnInitialize() {
+    //   traceMsg("Parse Builder Initialize - startupOnInitialize()");
+  }
+
+  /**
+  * Write trace statements.  
+  * System.out.println with prefix tagging used for simplicity.
+  */
+  //  private void traceMsg(String msg) {
+  //    if (PHPeclipsePlugin.DEBUG | traceEnabled)
+  //      System.out.println(
+  //        buildMode
+  //          + "<"
+  //          + getProject()
+  //          + "> "
+  //          + "\t\t\t"
+  //          + buildMark
+  //          + msg);
+  //  }
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserVisitor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserVisitor.java
new file mode 100644
index 0000000..5dbc801
--- /dev/null
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/builder/ParserVisitor.java
@@ -0,0 +1,71 @@
+package net.sourceforge.phpeclipse.builder;
+
+import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
+import net.sourceforge.phpeclipse.phpeditor.PHPParserAction;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IResourceDelta;
+import org.eclipse.core.resources.IResourceDeltaVisitor;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+
+/**
+ *
+ * @see org.eclipse.core.resources.IResourceDelta
+ * @see org.eclipse.core.resources.IResourceDeltaVisitor
+ */
+public class ParserVisitor implements IResourceDeltaVisitor {
+  final IProgressMonitor fMonitor;
+  public ParserVisitor(IProgressMonitor monitor) {
+    fMonitor = monitor;
+  }
+  
+	protected void checkCancel() {
+				if (fMonitor.isCanceled()) {
+					 throw new OperationCanceledException();
+				}
+		 }
+  /** 
+   * Visits the given resource delta.
+   * 
+   * @return <code>true</code> if the resource delta's children should
+   *		be visited; <code>false</code> if they should be skipped.
+   * @exception CoreException if the visit fails for some reason.
+   */
+  public boolean visit(IResourceDelta delta) throws CoreException {
+
+    IResource resource = delta.getResource();
+    int resourceType = resource.getType();
+		checkCancel();
+		
+    switch (delta.getKind()) {
+      case IResourceDelta.ADDED :
+        if (resourceType == IResource.FILE) {
+          if ((resource.getFileExtension() != null)
+            && PHPFileUtil.isPHPFile((IFile) resource)) {
+						fMonitor.worked(1);
+            fMonitor.subTask("Parsing: " + resource.getFullPath());
+            PHPParserAction.parseFile((IFile) resource);
+          }
+        }
+        break;
+
+      case IResourceDelta.CHANGED :
+        if (resourceType == IResource.FILE) {
+          if ((resource.getFileExtension() != null)
+            && PHPFileUtil.isPHPFile((IFile) resource)) {
+			  		fMonitor.worked(1);
+            fMonitor.subTask("Parsing: " + resource.getFullPath());
+            PHPParserAction.parseFile((IFile) resource);
+          }
+        }
+        break;
+
+      case IResourceDelta.REMOVED :
+        }
+    return true; // carry on
+  }
+
+}
\ No newline at end of file
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java
index 712a200..ac8fa19 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPEditor.java
@@ -346,11 +346,14 @@ public class PHPEditor
     super.doSave(monitor);
     // compile or not, according to the user preferences
     IPreferenceStore store = getPreferenceStore(); // fPHPPrefStore;
-    if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) {
-      IAction a = PHPParserAction.getInstance();
-      if (a != null)
-        a.run();
-    }
+
+    // the parse on save was changed to the eclipse "builders" concept
+    //    if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) {
+    //      IAction a = PHPParserAction.getInstance();
+    //      if (a != null)
+    //        a.run();
+    //    }
+
     //    if (SWT.getPlatform().equals("win32")) {
     //      IAction a = ShowExternalPreviewAction.getInstance();
     //      if (a != null)
@@ -393,20 +396,25 @@ public class PHPEditor
    */
   public void editorContextMenuAboutToShow(MenuManager menu) {
     super.editorContextMenuAboutToShow(menu);
-		menu.appendToGroup(ITextEditorActionConstants.GROUP_UNDO, new Separator(IContextMenuConstants.GROUP_OPEN));	
-		menu.insertAfter(IContextMenuConstants.GROUP_OPEN, new GroupMarker(IContextMenuConstants.GROUP_SHOW));	
-		
-		ActionContext context= new ActionContext(getSelectionProvider().getSelection());
-		fContextMenuGroup.setContext(context);
-		fContextMenuGroup.fillContextMenu(menu);
-		fContextMenuGroup.setContext(null);
-//    addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$
-//
-//    ActionContext context =
-//      new ActionContext(getSelectionProvider().getSelection());
-//    fContextMenuGroup.setContext(context);
-//    fContextMenuGroup.fillContextMenu(menu);
-//    fContextMenuGroup.setContext(null);
+    menu.appendToGroup(
+      ITextEditorActionConstants.GROUP_UNDO,
+      new Separator(IContextMenuConstants.GROUP_OPEN));
+    menu.insertAfter(
+      IContextMenuConstants.GROUP_OPEN,
+      new GroupMarker(IContextMenuConstants.GROUP_SHOW));
+
+    ActionContext context =
+      new ActionContext(getSelectionProvider().getSelection());
+    fContextMenuGroup.setContext(context);
+    fContextMenuGroup.fillContextMenu(menu);
+    fContextMenuGroup.setContext(null);
+    //    addAction(menu, ITextEditorActionConstants.GROUP_EDIT, "Format"); //$NON-NLS-1$
+    //
+    //    ActionContext context =
+    //      new ActionContext(getSelectionProvider().getSelection());
+    //    fContextMenuGroup.setContext(context);
+    //    fContextMenuGroup.fillContextMenu(menu);
+    //    fContextMenuGroup.setContext(null);
   }
 
   protected void updateStateDependentActions() {
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPParserAction.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPParserAction.java
index b40c10b..fbef0f3 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPParserAction.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/phpeditor/PHPParserAction.java
@@ -58,46 +58,53 @@ public class PHPParserAction extends TextEditorAction {
    */
   public void run() {
     boolean phpFlag = false;
-    try {
+		
+  //  try {
       fileToParse = getPHPFile();
-      if (fileToParse == null) {
-        // should never happen
-        System.err.println("Error : no file in the editor");
-        // should throw an exception
-        return;
-      }
-      String name = fileToParse.getName().toLowerCase();
-      for (int i = 0; i<EXTENSIONS.length; i++) {
-        if (name.endsWith(EXTENSIONS[i])) {
-          phpFlag = true;  // php file extension
-          break;
-        }
-      }
-      if (phpFlag) {
-        IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
-        if (store.getString(PHPeclipsePlugin.PHP_PARSER_DEFAULT).equals(PHPeclipsePlugin.PHP_INTERNAL_PARSER)) {
-          // first delete all the previous markers
-          fileToParse.deleteMarkers(IMarker.PROBLEM, false, 0);
-
-          //the tasks are removed here
-          fileToParse.deleteMarkers(IMarker.TASK, false, 0);
-
-          try {
-            InputStream iStream = fileToParse.getContents();
-            //        int c = iStream.read();
-            parse(iStream);
-            iStream.close();
-          } catch (IOException e) {
-          }
-        } else {
-          PHPParserSuperclass.phpExternalParse(fileToParse);
-        }
-      }
-    } catch (CoreException e) {
-    }
-
+			parseFile(fileToParse);
   }
 
+	public static void parseFile(IFile fileToParse) {
+			boolean phpFlag = false;
+			try {
+				
+				if (fileToParse == null) {
+					// should never happen
+					System.err.println("Error : no file in the editor");
+					// should throw an exception
+					return;
+				}
+				String name = fileToParse.getName().toLowerCase();
+				for (int i = 0; i<EXTENSIONS.length; i++) {
+					if (name.endsWith(EXTENSIONS[i])) {
+						phpFlag = true;  // php file extension
+						break;
+					}
+				}
+				if (phpFlag) {
+					IPreferenceStore store = PHPeclipsePlugin.getDefault().getPreferenceStore();
+					if (store.getString(PHPeclipsePlugin.PHP_PARSER_DEFAULT).equals(PHPeclipsePlugin.PHP_INTERNAL_PARSER)) {
+						// first delete all the previous markers
+						fileToParse.deleteMarkers(IMarker.PROBLEM, false, 0);
+
+						//the tasks are removed here
+						fileToParse.deleteMarkers(IMarker.TASK, false, 0);
+
+						try {
+							InputStream iStream = fileToParse.getContents();
+							//        int c = iStream.read();
+							parse(fileToParse,iStream);
+							iStream.close();
+						} catch (IOException e) {
+						}
+					} else {
+						PHPParserSuperclass.phpExternalParse(fileToParse);
+					}
+				}
+			} catch (CoreException e) {
+			}
+
+		}
   /**
    * Finds the file that's currently opened in the PHP Text Editor
    */
@@ -155,7 +162,7 @@ public class PHPParserAction extends TextEditorAction {
   //    return identifier.toString();
   //  }
 
-  protected void parse(InputStream iStream) {
+  protected static void parse(IFile fileToParse, InputStream iStream) {
 
     StringBuffer buf = new StringBuffer();
     int c0;
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/resourcesview/PHPProject.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/resourcesview/PHPProject.java
index e903be5..775c6d7 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/resourcesview/PHPProject.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/resourcesview/PHPProject.java
@@ -11,8 +11,10 @@ import javax.xml.parsers.SAXParserFactory;
 import net.sourceforge.phpeclipse.LoadPathEntry;
 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
 
+import org.eclipse.core.resources.ICommand;
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IProjectDescription;
 import org.eclipse.core.resources.IProjectNature;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
@@ -26,150 +28,201 @@ import org.xml.sax.SAXException;
 import org.xml.sax.XMLReader;
 
 public class PHPProject implements IProjectNature, PHPElement {
-	protected IProject fProject;
-	protected List loadPathEntries;
-	protected boolean scratched;
-
-	public PHPProject() {}
-
-	public void configure() throws CoreException {}
-
-	public void deconfigure() throws CoreException {}
-
-	public IProject getProject() {
-		return fProject;
-	}
-
-	protected IProject getProject(String name) {
-		return PHPeclipsePlugin.getWorkspace().getRoot().getProject(name);
-	}
-
-	public void setProject(IProject aProject) {
-		fProject = aProject;
-	}
-
-	public void addLoadPathEntry(IProject anotherPHPProject) {
-		scratched = true;
-
-		LoadPathEntry newEntry = new LoadPathEntry(anotherPHPProject);
-		getLoadPathEntries().add(newEntry);
-	}
-
-	public void removeLoadPathEntry(IProject anotherPHPProject) {
-		Iterator entries = getLoadPathEntries().iterator();
-		while (entries.hasNext()) {
-			LoadPathEntry entry = (LoadPathEntry) entries.next();
-			if (entry.getType() == LoadPathEntry.TYPE_PROJECT && entry.getProject().getName().equals(anotherPHPProject.getName())) {
-				getLoadPathEntries().remove(entry);
-				scratched = true;
-				break;
-			}
-		}
-	}
-
-	public List getLoadPathEntries() {
-		if (loadPathEntries == null) {
-			loadLoadPathEntries();
-		}
-
-		return loadPathEntries;
-	}
-
-	public List getReferencedProjects() {
-		List referencedProjects = new ArrayList();
-
-		Iterator iterator = getLoadPathEntries().iterator();
-		while (iterator.hasNext()) {
-			LoadPathEntry pathEntry = (LoadPathEntry) iterator.next();
-			if (pathEntry.getType() == LoadPathEntry.TYPE_PROJECT)
-				referencedProjects.add(pathEntry.getProject());
-		}
-
-		return referencedProjects;
-	}
-
-	protected void loadLoadPathEntries() {
-		loadPathEntries = new ArrayList();
-
-		IFile loadPathsFile = getLoadPathEntriesFile();
-
-		XMLReader reader = null;
-		try {
-			reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
-			reader.setContentHandler(getLoadPathEntriesContentHandler());
-			reader.parse(new InputSource(loadPathsFile.getContents()));
-		} catch (Exception e) {
-			//the file is nonextant or unreadable
-		}
-	}
-
-	protected ContentHandler getLoadPathEntriesContentHandler() {
-		return new ContentHandler() {
-			public void characters(char[] arg0, int arg1, int arg2) throws SAXException {}
-
-			public void endDocument() throws SAXException {}
-
-			public void endElement(String arg0, String arg1, String arg2) throws SAXException {}
-
-			public void endPrefixMapping(String arg0) throws SAXException {}
-
-			public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {}
-
-			public void processingInstruction(String arg0, String arg1) throws SAXException {}
-
-			public void setDocumentLocator(Locator arg0) {}
-
-			public void skippedEntity(String arg0) throws SAXException {}
-
-			public void startDocument() throws SAXException {}
-
-			public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
-				if ("pathentry".equals(qName))
-					if ("project".equals(atts.getValue("type"))) {
-						IPath referencedProjectPath = new Path(atts.getValue("path"));
-						IProject referencedProject = getProject(referencedProjectPath.lastSegment());
-						loadPathEntries.add(new LoadPathEntry(referencedProject));
-					}
-			}
-
-			public void startPrefixMapping(String arg0, String arg1) throws SAXException {}
-		};
-	}
-
-	protected IFile getLoadPathEntriesFile() {
-		return fProject.getFile(".loadpath");
-	}
-
-	public void save() throws CoreException {
-		if (scratched) {
-			InputStream xmlPath = new ByteArrayInputStream(getLoadPathXML().getBytes());
-			IFile loadPathsFile = getLoadPathEntriesFile();
-			if (!loadPathsFile.exists())
-				loadPathsFile.create(xmlPath, true, null);
-			else
-				loadPathsFile.setContents(xmlPath, true, false, null);
-
-			scratched = false;
-		}
-	}
-
-	protected String getLoadPathXML() {
-		StringBuffer buffer = new StringBuffer();
-		buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><loadpath>");
-
-		Iterator pathEntriesIterator = loadPathEntries.iterator();
-
-		while (pathEntriesIterator.hasNext()) {
-			LoadPathEntry entry = (LoadPathEntry) pathEntriesIterator.next();
-			buffer.append(entry.toXML());
-		}
-
-		buffer.append("</loadpath>");
-		return buffer.toString();
-	}
-	
-	public IResource getUnderlyingResource() {
-		return fProject;
-	}
+  protected IProject fProject;
+  protected List loadPathEntries;
+  protected boolean scratched;
+
+  public PHPProject() {
+  }
+
+  public void configure() throws CoreException {
+    //	get project description and then the associated build commands 
+    IProjectDescription desc = fProject.getDescription();
+    ICommand[] commands = desc.getBuildSpec();
+
+    // determine if builder already associated
+    boolean found = false;
+    for (int i = 0; i < commands.length; ++i) {
+      if (commands[i].getBuilderName().equals(PHPeclipsePlugin.BUILDER_PARSER_ID)) {
+        found = true;
+        break;
+      }
+    }
+
+    // add builder if not already in project
+    if (!found) {
+      ICommand command = desc.newCommand();
+      command.setBuilderName(PHPeclipsePlugin.BUILDER_PARSER_ID);
+      ICommand[] newCommands = new ICommand[commands.length + 1];
+
+      // Add it before other builders. 
+      System.arraycopy(commands, 0, newCommands, 1, commands.length);
+      newCommands[0] = command;
+      desc.setBuildSpec(newCommands);
+      fProject.setDescription(desc, null);
+    }
+  }
+
+  public void deconfigure() throws CoreException {
+  }
+
+  public IProject getProject() {
+    return fProject;
+  }
+
+  protected IProject getProject(String name) {
+    return PHPeclipsePlugin.getWorkspace().getRoot().getProject(name);
+  }
+
+  public void setProject(IProject aProject) {
+    fProject = aProject;
+  }
+
+  public void addLoadPathEntry(IProject anotherPHPProject) {
+    scratched = true;
+
+    LoadPathEntry newEntry = new LoadPathEntry(anotherPHPProject);
+    getLoadPathEntries().add(newEntry);
+  }
+
+  public void removeLoadPathEntry(IProject anotherPHPProject) {
+    Iterator entries = getLoadPathEntries().iterator();
+    while (entries.hasNext()) {
+      LoadPathEntry entry = (LoadPathEntry) entries.next();
+      if (entry.getType() == LoadPathEntry.TYPE_PROJECT
+        && entry.getProject().getName().equals(anotherPHPProject.getName())) {
+        getLoadPathEntries().remove(entry);
+        scratched = true;
+        break;
+      }
+    }
+  }
+
+  public List getLoadPathEntries() {
+    if (loadPathEntries == null) {
+      loadLoadPathEntries();
+    }
+
+    return loadPathEntries;
+  }
+
+  public List getReferencedProjects() {
+    List referencedProjects = new ArrayList();
+
+    Iterator iterator = getLoadPathEntries().iterator();
+    while (iterator.hasNext()) {
+      LoadPathEntry pathEntry = (LoadPathEntry) iterator.next();
+      if (pathEntry.getType() == LoadPathEntry.TYPE_PROJECT)
+        referencedProjects.add(pathEntry.getProject());
+    }
+
+    return referencedProjects;
+  }
+
+  protected void loadLoadPathEntries() {
+    loadPathEntries = new ArrayList();
+
+    IFile loadPathsFile = getLoadPathEntriesFile();
+
+    XMLReader reader = null;
+    try {
+      reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
+      reader.setContentHandler(getLoadPathEntriesContentHandler());
+      reader.parse(new InputSource(loadPathsFile.getContents()));
+    } catch (Exception e) {
+      //the file is nonextant or unreadable
+    }
+  }
+
+  protected ContentHandler getLoadPathEntriesContentHandler() {
+    return new ContentHandler() {
+      public void characters(char[] arg0, int arg1, int arg2)
+        throws SAXException {
+      }
+
+      public void endDocument() throws SAXException {
+      }
+
+      public void endElement(String arg0, String arg1, String arg2)
+        throws SAXException {
+      }
+
+      public void endPrefixMapping(String arg0) throws SAXException {
+      }
+
+      public void ignorableWhitespace(char[] arg0, int arg1, int arg2)
+        throws SAXException {
+      }
+
+      public void processingInstruction(String arg0, String arg1)
+        throws SAXException {
+      }
+
+      public void setDocumentLocator(Locator arg0) {
+      }
+
+      public void skippedEntity(String arg0) throws SAXException {
+      }
+
+      public void startDocument() throws SAXException {
+      }
+
+      public void startElement(
+        String namespaceURI,
+        String localName,
+        String qName,
+        Attributes atts)
+        throws SAXException {
+        if ("pathentry".equals(qName))
+          if ("project".equals(atts.getValue("type"))) {
+            IPath referencedProjectPath = new Path(atts.getValue("path"));
+            IProject referencedProject =
+              getProject(referencedProjectPath.lastSegment());
+            loadPathEntries.add(new LoadPathEntry(referencedProject));
+          }
+      }
+
+      public void startPrefixMapping(String arg0, String arg1)
+        throws SAXException {
+      }
+    };
+  }
+
+  protected IFile getLoadPathEntriesFile() {
+    return fProject.getFile(".loadpath");
+  }
+
+  public void save() throws CoreException {
+    if (scratched) {
+      InputStream xmlPath =
+        new ByteArrayInputStream(getLoadPathXML().getBytes());
+      IFile loadPathsFile = getLoadPathEntriesFile();
+      if (!loadPathsFile.exists())
+        loadPathsFile.create(xmlPath, true, null);
+      else
+        loadPathsFile.setContents(xmlPath, true, false, null);
+
+      scratched = false;
+    }
+  }
+
+  protected String getLoadPathXML() {
+    StringBuffer buffer = new StringBuffer();
+    buffer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?><loadpath>");
+
+    Iterator pathEntriesIterator = loadPathEntries.iterator();
+
+    while (pathEntriesIterator.hasNext()) {
+      LoadPathEntry entry = (LoadPathEntry) pathEntriesIterator.next();
+      buffer.append(entry.toXML());
+    }
+
+    buffer.append("</loadpath>");
+    return buffer.toString();
+  }
+
+  public IResource getUnderlyingResource() {
+    return fProject;
+  }
 
 }
diff --git a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/views/PHPConsole.java b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/views/PHPConsole.java
index 638ca71..9529dd2 100644
--- a/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/views/PHPConsole.java
+++ b/net.sourceforge.phpeclipse/src/net/sourceforge/phpeclipse/views/PHPConsole.java
@@ -36,15 +36,12 @@ import org.eclipse.jface.text.TextViewer;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.custom.StyledText;
 import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Menu;
 import org.eclipse.ui.IActionBars;
 import org.eclipse.ui.IWorkbenchActionConstants;
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.PartInitException;
-import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.part.ViewPart;
 
 /**
@@ -53,15 +50,16 @@ import org.eclipse.ui.part.ViewPart;
  */
 public class PHPConsole extends ViewPart {
 
-  public static final String CONSOLE_ID = "net.sourceforge.phpeclipse.views.phpconsoleview";
+  public static final String CONSOLE_ID =
+    "net.sourceforge.phpeclipse.views.phpconsoleview";
   private int COMMAND_COMBO_SIZE = 10;
 
   private TextViewer fViewer = null;
   private Document fDocument = null;
   private StyledText fStyledText;
   // private Combo fCommandCombo;
-//  private ProcessOutputWriter consoleOut;
-//  private ProcessOutputWriter consoleErr;
+  //  private ProcessOutputWriter consoleOut;
+  //  private ProcessOutputWriter consoleErr;
 
   // private Action goAction;
 
@@ -101,20 +99,20 @@ public class PHPConsole extends ViewPart {
    * @see ViewPart#createPartControl
    */
   public void createPartControl(Composite parent) {
-//    Composite container = new Composite(parent, SWT.NULL);
-//    //   control = container;
-//    GridLayout layout = new GridLayout();
-//    layout.marginWidth = 0;
-//    layout.marginHeight = 0;
-//    layout.verticalSpacing = 0;
-//    container.setLayout(layout);
-//    Composite navContainer = new Composite(container, SWT.NONE);
-//    layout = new GridLayout();
-//    layout.numColumns = 2;
-//    layout.marginHeight = 1;
-//    navContainer.setLayout(layout);
-//    createCommandBar(navContainer);
-//    navContainer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+    //    Composite container = new Composite(parent, SWT.NULL);
+    //    //   control = container;
+    //    GridLayout layout = new GridLayout();
+    //    layout.marginWidth = 0;
+    //    layout.marginHeight = 0;
+    //    layout.verticalSpacing = 0;
+    //    container.setLayout(layout);
+    //    Composite navContainer = new Composite(container, SWT.NONE);
+    //    layout = new GridLayout();
+    //    layout.numColumns = 2;
+    //    layout.marginHeight = 1;
+    //    navContainer.setLayout(layout);
+    //    createCommandBar(navContainer);
+    //    navContainer.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
 
     fViewer = new TextViewer(parent, SWT.WRAP | SWT.V_SCROLL | SWT.H_SCROLL);
     GridData viewerData = new GridData(GridData.FILL_BOTH);
@@ -122,7 +120,8 @@ public class PHPConsole extends ViewPart {
     fViewer.setEditable(false);
 
     fStyledText = fViewer.getTextWidget();
-    fStyledText.setFont(JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT));
+    fStyledText.setFont(
+      JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT));
 
     cutAction.setText("Cut");
     copyAction.setText("Copy");
@@ -147,8 +146,8 @@ public class PHPConsole extends ViewPart {
   }
 
   private void createCommandBar(Composite parent) {
-//    Label addressLabel = new Label(parent, SWT.NONE);
-//    addressLabel.setText("Command:");
+    //    Label addressLabel = new Label(parent, SWT.NONE);
+    //    addressLabel.setText("Command:");
 
     //    fCommandCombo = new Combo(parent, SWT.DROP_DOWN | SWT.BORDER);
     //    fCommandCombo.addModifyListener(new ModifyListener() {
@@ -368,10 +367,20 @@ public class PHPConsole extends ViewPart {
   }
 
   public static PHPConsole getInstance() {
-    IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+    // IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+    IWorkbenchPage page =
+      PHPeclipsePlugin
+        .getDefault()
+        .getWorkbench()
+        .getActiveWorkbenchWindow()
+        .getActivePage();
     PHPConsole console = (PHPConsole) page.findView(PHPConsole.CONSOLE_ID);
 
-    if (PHPeclipsePlugin.getDefault().getPreferenceStore().getBoolean(PHPeclipsePlugin.SHOW_OUTPUT_IN_CONSOLE) == true) {
+    if (PHPeclipsePlugin
+      .getDefault()
+      .getPreferenceStore()
+      .getBoolean(PHPeclipsePlugin.SHOW_OUTPUT_IN_CONSOLE) 
+      == true) {
       try {
         page.showView(PHPConsole.CONSOLE_ID);
         if (console == null) {
@@ -383,7 +392,8 @@ public class PHPConsole extends ViewPart {
             IStatus.ERROR,
             PHPeclipsePlugin.getPluginId(),
             0,
-            PHPActionMessages.getString("PHPStartApacheAction.consoleViewOpeningProblem"),
+            PHPActionMessages.getString(
+              "PHPStartApacheAction.consoleViewOpeningProblem"),
             e));
       }
     }
@@ -400,7 +410,8 @@ public class PHPConsole extends ViewPart {
   /**
    * Creates a string buffer from the given input stream
    */
-  public static String getStringFromStream(InputStream stream) throws IOException {
+  public static String getStringFromStream(InputStream stream)
+    throws IOException {
     StringBuffer buffer = new StringBuffer();
     byte[] b = new byte[100];
     int finished = 0;
@@ -451,7 +462,8 @@ public class PHPConsole extends ViewPart {
 
     public void run() {
       try {
-        BufferedReader in = new BufferedReader(new InputStreamReader(fInputStream));
+        BufferedReader in =
+          new BufferedReader(new InputStreamReader(fInputStream));
 
         String line;
         while ((line = in.readLine()) != null) {
-- 
1.7.1