[med-svn] [libjung-java] 02/02: initial Debianization

Michael Crusoe misterc-guest at moszumanska.debian.org
Fri Feb 13 22:55:16 UTC 2015


This is an automated email from the git hooks/post-receive script.

misterc-guest pushed a commit to branch master
in repository libjung-java.

commit 6fbbe8d563ab6602827975bed6490aea83fd0882
Author: Michael R. Crusoe <mcrusoe at msu.edu>
Date:   Fri Feb 13 11:56:31 2015 -0500

    initial Debianization
---
 debian/changelog             |     5 +
 debian/compat                |     1 +
 debian/control               |    37 +
 debian/copyright             |    54 +
 debian/createmanpages        |    16 +
 debian/patches/collections15 | 53359 +++++++++++++++++++++++++++++++++++++++++
 debian/patches/series        |     1 +
 debian/rules                 |    51 +
 debian/source/format         |     1 +
 debian/upstream/metadata     |    12 +
 debian/watch                 |    37 +
 11 files changed, 53574 insertions(+)

diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..3abf8e0
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+libjung-java (2.0.1-1) UNRELEASED; urgency=low
+
+  * Initial release (Closes: #<bug>)
+
+ -- Michael R. Crusoe <mcrusoe at msu.edu>  Fri, 13 Feb 2015 11:52:45 -0500 
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..ec63514
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..41442f1
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,37 @@
+Source: libjung-java
+Section: java
+Priority: optional
+Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
+Uploaders: Michael R. Crusoe <mcrusoe at msu.edu>
+Build-Depends: debhelper (>= 9), javahelper, libcommons-collections4-java
+Standards-Version: 3.9.6
+Vcs-Browser: http://anonscm.debian.org/viewvc/debian-med/trunk/packages/<pkg>/trunk/
+Vcs-Svn: svn://anonscm.debian.org/debian-med/trunk/packages/<pkg>/trunk/
+Homepage: http://jung.sourceforge.net/
+
+Package: libjung-java
+Architecture: any
+Depends: ${java:Depends}, ${misc:Depends}
+Description: Java Universal Network/Graph Framework
+ JUNG provides a common and extendible language for the modeling, analysis, and
+ visualization of data that can be represented as a graph or network.
+ .
+ The JUNG architecture is designed to support a variety of representations of
+ entities and their relations, such as directed and undirected graphs,
+ multi-modal graphs, graphs with parallel edges, and hypergraphs. It provides
+ a mechanism for annotating graphs, entities, and relations with metadata. This
+ facilitates the creation of analytic tools for complex data sets that can
+ examine the relations between entities as well as the metadata attached to each
+ entity and relation.
+ .
+ The current distribution of JUNG includes implementations of a number of
+ algorithms from graph theory, data mining, and social network analysis, such as
+ routines for clustering, decomposition, optimization, random graph generation,
+ statistical analysis, and calculation of network distances, flows, and
+ importance measures (centrality, PageRank, HITS, etc.).
+ .
+ JUNG also provides a visualization framework that makes it easy to construct
+ tools for the interactive exploration of network data. Users can use one of the
+ layout algorithms provided, or use the framework to create their own custom
+ layouts. In addition, filtering mechanisms are provided which allow users to
+ focus their attention, or their algorithms, on specific portions of the graph.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..66b0a1f
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,54 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: JUNG
+Source: http://sourceforge.net/projects/jung/files/jung/jung-2.0.1/jung2-2_0_1-sources.zip/download
+
+Files: *
+Copyright: © 2003-2004,  Regents of the University of California and the JUNG Project
+License: BSD-3-clause
+
+Files: debian/*
+Copyright: © 2014 Michigan State University
+License: BSD-3-clause
+
+Files: debian/patches/collections15
+Copyright: 1999-2004, The Apache Software Foundation
+Comment: Source http://sourceforge.net/projects/collections/
+License: Apache-2.0
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ .
+     http://www.apache.org/licenses/LICENSE-2.0
+ .
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ .
+ On Debian systems, the complete text of the Apache License version 2.0
+ can be found in "/usr/share/common-licenses/Apache-2.0".
+
+License: BSD-3-clause
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ .
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the University of California nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/debian/createmanpages b/debian/createmanpages
new file mode 100755
index 0000000..febcd91
--- /dev/null
+++ b/debian/createmanpages
@@ -0,0 +1,16 @@
+#!/bin/sh
+MANDIR=debian
+mkdir -p $MANDIR
+
+VERSION=`dpkg-parsechangelog | awk '/^Version:/ {print $2}' | sed -e 's/^[0-9]*://' -e 's/-.*//' -e 's/[+~]dfsg$//'`
+
+help2man --no-info --no-discard-stderr --help-option=" " \
+         --name='<optional description of the program>' \
+            --version-string="$VERSION" <programname> > $MANDIR/<programname>.1
+
+cat <<EOT
+Please enhance the help2man output.
+The following web page might be helpful in doing so:
+    http://liw.fi/manpages/
+EOT
+
diff --git a/debian/patches/collections15 b/debian/patches/collections15
new file mode 100644
index 0000000..b5a96a1
--- /dev/null
+++ b/debian/patches/collections15
@@ -0,0 +1,53359 @@
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/ArrayStack.java
+@@ -0,0 +1,195 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.ArrayList;
++import java.util.EmptyStackException;
++
++/**
++ * An implementation of the {@link java.util.Stack} API that is based on an
++ * <code>ArrayList</code> instead of a <code>Vector</code>, so it is not
++ * synchronized to protect against multi-threaded access.  The implementation
++ * is therefore operates faster in environments where you do not need to
++ * worry about multiple thread contention.
++ * <p/>
++ * The removal order of an <code>ArrayStack</code> is based on insertion
++ * order: The most recently added element is removed first.  The iteration
++ * order is <i>not</i> the same as the removal order.  The iterator returns
++ * elements from the bottom up, whereas the {@link #remove()} method removes
++ * them from the top down.
++ * <p/>
++ * Unlike <code>Stack</code>, <code>ArrayStack</code> accepts null entries.
++ *
++ * @author Craig R. McClanahan
++ * @author Paul Jack
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @see java.util.Stack
++ * @since Commons Collections 1.0
++ */
++public class ArrayStack <E> extends ArrayList<E> implements Buffer<E> {
++
++    /**
++     * Ensure serialization compatibility
++     */
++    private static final long serialVersionUID = 2130079159931574599L;
++
++    /**
++     * Constructs a new empty <code>ArrayStack</code>. The initial size
++     * is controlled by <code>ArrayList</code> and is currently 10.
++     */
++    public ArrayStack() {
++        super();
++    }
++
++    /**
++     * Constructs a new empty <code>ArrayStack</code> with an initial size.
++     *
++     * @param initialSize the initial size to use
++     * @throws IllegalArgumentException if the specified initial size
++     *                                  is negative
++     */
++    public ArrayStack(int initialSize) {
++        super(initialSize);
++    }
++
++    /**
++     * Return <code>true</code> if this stack is currently empty.
++     * <p/>
++     * This method exists for compatibility with <code>java.util.Stack</code>.
++     * New users of this class should use <code>isEmpty</code> instead.
++     *
++     * @return true if the stack is currently empty
++     */
++    public boolean empty() {
++        return isEmpty();
++    }
++
++    /**
++     * Returns the top item off of this stack without removing it.
++     *
++     * @return the top item on the stack
++     * @throws EmptyStackException if the stack is empty
++     */
++    public E peek() throws EmptyStackException {
++        int n = size();
++        if (n <= 0) {
++            throw new EmptyStackException();
++        } else {
++            return get(n - 1);
++        }
++    }
++
++    /**
++     * Returns the n'th item down (zero-relative) from the top of this
++     * stack without removing it.
++     *
++     * @param n the number of items down to go
++     * @return the n'th item on the stack, zero relative
++     * @throws EmptyStackException if there are not enough items on the
++     *                             stack to satisfy this request
++     */
++    public E peek(int n) throws EmptyStackException {
++        int m = (size() - n) - 1;
++        if (m < 0) {
++            throw new EmptyStackException();
++        } else {
++            return get(m);
++        }
++    }
++
++    /**
++     * Pops the top item off of this stack and return it.
++     *
++     * @return the top item on the stack
++     * @throws EmptyStackException if the stack is empty
++     */
++    public E pop() throws EmptyStackException {
++        int n = size();
++        if (n <= 0) {
++            throw new EmptyStackException();
++        } else {
++            return remove(n - 1);
++        }
++    }
++
++    /**
++     * Pushes a new item onto the top of this stack. The pushed item is also
++     * returned. This is equivalent to calling <code>add</code>.
++     *
++     * @param item the item to be added
++     * @return the item just pushed
++     */
++    public E push(E item) {
++        add(item);
++        return item;
++    }
++
++    /**
++     * Returns the one-based position of the distance from the top that the
++     * specified object exists on this stack, where the top-most element is
++     * considered to be at distance <code>1</code>.  If the object is not
++     * present on the stack, return <code>-1</code> instead.  The
++     * <code>equals()</code> method is used to compare to the items
++     * in this stack.
++     *
++     * @param object the object to be searched for
++     * @return the 1-based depth into the stack of the object, or -1 if not found
++     */
++    public int search(E object) {
++        int i = size() - 1;        // Current index
++        int n = 1;                 // Current distance
++        while (i >= 0) {
++            E current = get(i);
++            if ((object == null && current == null) || (object != null && object.equals(current))) {
++                return n;
++            }
++            i--;
++            n++;
++        }
++        return -1;
++    }
++
++    /**
++     * Returns the element on the top of the stack.
++     *
++     * @return the element on the top of the stack
++     * @throws BufferUnderflowException if the stack is empty
++     */
++    public E get() {
++        int size = size();
++        if (size == 0) {
++            throw new BufferUnderflowException();
++        }
++        return get(size - 1);
++    }
++
++    /**
++     * Removes the element on the top of the stack.
++     *
++     * @return the removed element
++     * @throws BufferUnderflowException if the stack is empty
++     */
++    public E remove() {
++        int size = size();
++        if (size == 0) {
++            throw new BufferUnderflowException();
++        }
++        return remove(size - 1);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/Bag.java
+@@ -0,0 +1,221 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Set;
++
++/**
++ * Defines a collection that counts the number of times an object appears in
++ * the collection.
++ * <p/>
++ * Suppose you have a Bag that contains <code>{a, a, b, c}</code>.
++ * Calling {@link #getCount(Object)} on <code>a</code> would return 2, while
++ * calling {@link #uniqueSet()} would return <code>{a, b, c}</code>.
++ * <p/>
++ * <i>NOTE: This interface violates the {@link Collection} contract.</i>
++ * The behavior specified in many of these methods is <i>not</i> the same
++ * as the behavior specified by <code>Collection</code>.
++ * The noncompliant methods are clearly marked with "(Violation)".
++ * Exercise caution when using a bag as a <code>Collection</code>.
++ * <p/>
++ * This violation resulted from the original specification of this interface.
++ * In an ideal world, the interface would be changed to fix the problems, however
++ * it has been decided to maintain backwards compatibility instead.
++ *
++ * @author Chuck Burdick
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.0
++ */
++public interface Bag <E> extends Collection<E> {
++
++    /**
++     * Returns the number of occurrences (cardinality) of the given
++     * object currently in the bag. If the object does not exist in the
++     * bag, return 0.
++     *
++     * @param object the object to search for
++     * @return the number of occurrences of the object, zero if not found
++     */
++    int getCount(E object);
++
++    /**
++     * <i>(Violation)</i>
++     * Adds one copy the specified object to the Bag.
++     * <p/>
++     * If the object is already in the {@link #uniqueSet()} then increment its
++     * count as reported by {@link #getCount(Object)}. Otherwise add it to the
++     * {@link #uniqueSet()} and report its count as 1.
++     * <p/>
++     * Since this method always increases the size of the bag,
++     * according to the {@link Collection#add(Object)} contract, it
++     * should always return <code>true</code>.  Since it sometimes returns
++     * <code>false</code>, this method violates the contract.
++     *
++     * @param object the object to add
++     * @return <code>true</code> if the object was not already in the <code>uniqueSet</code>
++     */
++    boolean add(E object);
++
++    /**
++     * Adds <code>nCopies</code> copies of the specified object to the Bag.
++     * <p/>
++     * If the object is already in the {@link #uniqueSet()} then increment its
++     * count as reported by {@link #getCount(Object)}. Otherwise add it to the
++     * {@link #uniqueSet()} and report its count as <code>nCopies</code>.
++     *
++     * @param object  the object to add
++     * @param nCopies the number of copies to add
++     * @return <code>true</code> if the object was not already in the <code>uniqueSet</code>
++     */
++    boolean add(E object, int nCopies);
++
++    /**
++     * <i>(Violation)</i>
++     * Removes all occurrences of the given object from the bag.
++     * <p/>
++     * This will also remove the object from the {@link #uniqueSet()}.
++     * <p/>
++     * According to the {@link Collection#remove(Object)} method,
++     * this method should only remove the <i>first</i> occurrence of the
++     * given object, not <i>all</i> occurrences.
++     *
++     * @return <code>true</code> if this call changed the collection
++     */
++    boolean remove(Object object);
++
++    /**
++     * Removes <code>nCopies</code> copies of the specified object from the Bag.
++     * <p/>
++     * If the number of copies to remove is greater than the actual number of
++     * copies in the Bag, no error is thrown.
++     *
++     * @param object  the object to remove
++     * @param nCopies the number of copies to remove
++     * @return <code>true</code> if this call changed the collection
++     */
++    boolean remove(E object, int nCopies);
++
++    /**
++     * Returns a {@link Set} of unique elements in the Bag.
++     * <p/>
++     * Uniqueness constraints are the same as those in {@link java.util.Set}.
++     *
++     * @return the Set of unique Bag elements
++     */
++    Set<E> uniqueSet();
++
++    /**
++     * Returns the total number of items in the bag across all types.
++     *
++     * @return the total size of the Bag
++     */
++    int size();
++
++    /**
++     * <i>(Violation)</i>
++     * Returns <code>true</code> if the bag contains all elements in
++     * the given collection, respecting cardinality.  That is, if the
++     * given collection <code>coll</code> contains <code>n</code> copies
++     * of a given object, calling {@link #getCount(Object)} on that object must
++     * be <code>>= n</code> for all <code>n</code> in <code>coll</code>.
++     * <p/>
++     * The {@link Collection#containsAll(Collection)} method specifies
++     * that cardinality should <i>not</i> be respected; this method should
++     * return true if the bag contains at least one of every object contained
++     * in the given collection.
++     *
++     * @param coll the collection to check against
++     * @return <code>true</code> if the Bag contains all the collection
++     */
++    boolean containsAll(Collection<?> coll);
++
++    /**
++     * <i>(Violation)</i>
++     * Remove all elements represented in the given collection,
++     * respecting cardinality.  That is, if the given collection
++     * <code>coll</code> contains <code>n</code> copies of a given object,
++     * the bag will have <code>n</code> fewer copies, assuming the bag
++     * had at least <code>n</code> copies to begin with.
++     * <p/>
++     * <P>The {@link Collection#removeAll(Collection)} method specifies
++     * that cardinality should <i>not</i> be respected; this method should
++     * remove <i>all</i> occurrences of every object contained in the
++     * given collection.
++     *
++     * @param coll the collection to remove
++     * @return <code>true</code> if this call changed the collection
++     */
++    boolean removeAll(Collection<?> coll);
++
++    /**
++     * <i>(Violation)</i>
++     * Remove any members of the bag that are not in the given
++     * collection, respecting cardinality.  That is, if the given
++     * collection <code>coll</code> contains <code>n</code> copies of a
++     * given object and the bag has <code>m > n</code> copies, then
++     * delete <code>m - n</code> copies from the bag.  In addition, if
++     * <code>e</code> is an object in the bag but
++     * <code>!coll.contains(e)</code>, then remove <code>e</code> and any
++     * of its copies.
++     * <p/>
++     * <P>The {@link Collection#retainAll(Collection)} method specifies
++     * that cardinality should <i>not</i> be respected; this method should
++     * keep <i>all</i> occurrences of every object contained in the
++     * given collection.
++     *
++     * @param coll the collection to retain
++     * @return <code>true</code> if this call changed the collection
++     */
++    boolean retainAll(Collection<?> coll);
++
++    /**
++     * Returns an {@link Iterator} over the entire set of members,
++     * including copies due to cardinality. This iterator is fail-fast
++     * and will not tolerate concurrent modifications.
++     *
++     * @return iterator over all elements in the Bag
++     */
++    Iterator<E> iterator();
++
++    // The following is not part of the formal Bag interface, however where possible
++    // Bag implementations should follow these comments.
++    //    /**
++    //     * Compares this Bag to another.
++    //     * This Bag equals another Bag if it contains the same number of occurrences of
++    //     * the same elements.
++    //     * This equals definition is compatible with the Set interface.
++    //     *
++    //     * @param obj  the Bag to compare to
++    //     * @return true if equal
++    //     */
++    //    boolean equals(Object obj);
++    //
++    //    /**
++    //     * Gets a hash code for the Bag compatible with the definition of equals.
++    //     * The hash code is defined as the sum total of a hash code for each element.
++    //     * The per element hash code is defined as
++    //     * <code>(e==null ? 0 : e.hashCode()) ^ noOccurances)</code>.
++    //     * This hash code definition is compatible with the Set interface.
++    //     *
++    //     * @return the hash code of the Bag
++    //     */
++    //    int hashCode();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/BagUtils.java
+@@ -0,0 +1,236 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.bag.*;
++
++/**
++ * Provides utility methods and decorators for
++ * {@link Bag} and {@link SortedBag} instances.
++ *
++ * @author Paul Jack
++ * @author Stephen Colebourne
++ * @author Andrew Freeman
++ * @author Matt Hall, John Watkinson, Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.1
++ */
++public class BagUtils {
++
++    /**
++     * An empty unmodifiable bag.
++     */
++    public static final Bag EMPTY_BAG = UnmodifiableBag.decorate(new HashBag());
++
++    /**
++     * An empty unmodifiable sorted bag.
++     */
++    public static final Bag EMPTY_SORTED_BAG = UnmodifiableSortedBag.decorate(new TreeBag());
++
++    /**
++     * Instantiation of BagUtils is not intended or required.
++     * However, some tools require an instance to operate.
++     */
++    public BagUtils() {
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a synchronized (thread-safe) bag backed by the given bag.
++     * In order to guarantee serial access, it is critical that all
++     * access to the backing bag is accomplished through the returned bag.
++     * <p/>
++     * It is imperative that the user manually synchronize on the returned
++     * bag when iterating over it:
++     * <p/>
++     * <pre>
++     * Bag bag = BagUtils.synchronizedBag(new HashBag());
++     * ...
++     * synchronized(bag) {
++     *     Iterator i = bag.iterator(); // Must be in synchronized block
++     *     while (i.hasNext())
++     *         foo(i.next());
++     *     }
++     * }
++     * </pre>
++     * <p/>
++     * Failure to follow this advice may result in non-deterministic
++     * behavior.
++     *
++     * @param bag the bag to synchronize, must not be null
++     * @return a synchronized bag backed by that bag
++     * @throws IllegalArgumentException if the Bag is null
++     */
++    public static <E> Bag<E> synchronizedBag(Bag<E> bag) {
++        return SynchronizedBag.decorate(bag);
++    }
++
++    /**
++     * Returns an unmodifiable view of the given bag.  Any modification
++     * attempts to the returned bag will raise an
++     * {@link UnsupportedOperationException}.
++     *
++     * @param bag the bag whose unmodifiable view is to be returned, must not be null
++     * @return an unmodifiable view of that bag
++     * @throws IllegalArgumentException if the Bag is null
++     */
++    public static <E> Bag<E> unmodifiableBag(Bag<E> bag) {
++        return UnmodifiableBag.decorate(bag);
++    }
++
++    /**
++     * Returns a predicated (validating) bag backed by the given bag.
++     * <p/>
++     * Only objects that pass the test in the given predicate can be added to the bag.
++     * Trying to add an invalid object results in an IllegalArgumentException.
++     * It is important not to use the original bag after invoking this method,
++     * as it is a backdoor for adding invalid objects.
++     *
++     * @param bag       the bag to predicate, must not be null
++     * @param predicate the predicate for the bag, must not be null
++     * @return a predicated bag backed by the given bag
++     * @throws IllegalArgumentException if the Bag or Predicate is null
++     */
++    public static <E> Bag<E> predicatedBag(Bag<E> bag, Predicate<? super E> predicate) {
++        return PredicatedBag.decorate(bag, predicate);
++    }
++
++    /**
++     * Returns a typed bag backed by the given bag.
++     * <p/>
++     * Only objects of the specified type can be added to the bag.
++     *
++     * @param bag  the bag to limit to a specific type, must not be null
++     * @param type the type of objects which may be added to the bag
++     * @return a typed bag backed by the specified bag
++     * @deprecated Java 1.5 generics makes this method no longer useful.
++     */
++    public static <E> Bag<E> typedBag(Bag<E> bag, Class<E> type) {
++        return TypedBag.decorate(bag, type);
++    }
++
++    /**
++     * Returns a transformed bag backed by the given bag.
++     * <p/>
++     * Each object is passed through the transformer as it is added to the
++     * Bag. It is important not to use the original bag after invoking this
++     * method, as it is a backdoor for adding untransformed objects.
++     *
++     * @param bag         the bag to predicate, must not be null
++     * @param transformer the transformer for the bag, must not be null
++     * @return a transformed bag backed by the given bag
++     * @throws IllegalArgumentException if the Bag or Transformer is null
++     * @deprecated TransformedCollections are not type-safe in Java 1.5.
++     */
++    public static <I,O> Bag<O> transformedBag(Bag<I> bag, Transformer<I, O> transformer) {
++        return TransformedBag.decorate(bag, transformer);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a synchronized (thread-safe) sorted bag backed by the given
++     * sorted bag.
++     * In order to guarantee serial access, it is critical that all
++     * access to the backing bag is accomplished through the returned bag.
++     * <p/>
++     * It is imperative that the user manually synchronize on the returned
++     * bag when iterating over it:
++     * <p/>
++     * <pre>
++     * SortedBag bag = BagUtils.synchronizedSortedBag(new TreeBag());
++     * ...
++     * synchronized(bag) {
++     *     Iterator i = bag.iterator(); // Must be in synchronized block
++     *     while (i.hasNext())
++     *         foo(i.next());
++     *     }
++     * }
++     * </pre>
++     * <p/>
++     * Failure to follow this advice may result in non-deterministic
++     * behavior.
++     *
++     * @param bag the bag to synchronize, must not be null
++     * @return a synchronized bag backed by that bag
++     * @throws IllegalArgumentException if the SortedBag is null
++     */
++    public static <E> SortedBag<E> synchronizedSortedBag(SortedBag<E> bag) {
++        return SynchronizedSortedBag.decorate(bag);
++    }
++
++    /**
++     * Returns an unmodifiable view of the given sorted bag.  Any modification
++     * attempts to the returned bag will raise an
++     * {@link UnsupportedOperationException}.
++     *
++     * @param bag the bag whose unmodifiable view is to be returned, must not be null
++     * @return an unmodifiable view of that bag
++     * @throws IllegalArgumentException if the SortedBag is null
++     */
++    public static <E> SortedBag<E> unmodifiableSortedBag(SortedBag<E> bag) {
++        return UnmodifiableSortedBag.decorate(bag);
++    }
++
++    /**
++     * Returns a predicated (validating) sorted bag backed by the given sorted bag.
++     * <p/>
++     * Only objects that pass the test in the given predicate can be added to the bag.
++     * Trying to add an invalid object results in an IllegalArgumentException.
++     * It is important not to use the original bag after invoking this method,
++     * as it is a backdoor for adding invalid objects.
++     *
++     * @param bag       the sorted bag to predicate, must not be null
++     * @param predicate the predicate for the bag, must not be null
++     * @return a predicated bag backed by the given bag
++     * @throws IllegalArgumentException if the SortedBag or Predicate is null
++     */
++    public static <E> SortedBag<E> predicatedSortedBag(SortedBag<E> bag, Predicate<? super E> predicate) {
++        return PredicatedSortedBag.decorate(bag, predicate);
++    }
++
++    /**
++     * Returns a typed sorted bag backed by the given bag.
++     * <p/>
++     * Only objects of the specified type can be added to the bag.
++     *
++     * @param bag  the bag to limit to a specific type, must not be null
++     * @param type the type of objects which may be added to the bag
++     * @return a typed bag backed by the specified bag
++     * @deprecated Java 1.5 generics makes this method no longer useful.
++     */
++    public static <E> SortedBag<E> typedSortedBag(SortedBag<E> bag, Class<E> type) {
++        return TypedSortedBag.decorate(bag, type);
++    }
++
++    /**
++     * Returns a transformed sorted bag backed by the given bag.
++     * <p/>
++     * Each object is passed through the transformer as it is added to the
++     * Bag. It is important not to use the original bag after invoking this
++     * method, as it is a backdoor for adding untransformed objects.
++     *
++     * @param bag         the bag to predicate, must not be null
++     * @param transformer the transformer for the bag, must not be null
++     * @return a transformed bag backed by the given bag
++     * @throws IllegalArgumentException if the Bag or Transformer is null
++     * @deprecated This breaks the java.util.Collection interface in Java 1.5. It is recommended that it not be used.
++     */
++    public static <I,O> SortedBag<O> transformedSortedBag(SortedBag<I> bag, Transformer<I, O> transformer) {
++        return TransformedSortedBag.decorate(bag, transformer);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/BeanMap.java
+@@ -0,0 +1,733 @@
++// GenericsNote: Converted to <String,Object>.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.keyvalue.AbstractMapEntry;
++import org.apache.commons.collections15.list.UnmodifiableList;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.beans.BeanInfo;
++import java.beans.IntrospectionException;
++import java.beans.Introspector;
++import java.beans.PropertyDescriptor;
++import java.lang.reflect.Constructor;
++import java.lang.reflect.InvocationTargetException;
++import java.lang.reflect.Method;
++import java.util.*;
++
++/**
++ * An implementation of Map for JavaBeans which uses introspection to
++ * get and put properties in the bean.
++ * <p/>
++ * If an exception occurs during attempts to get or set a property then the
++ * property is considered non existent in the Map
++ * <p/>
++ *
++ * @author James Strachan
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 1.0
++ */
++public class BeanMap extends AbstractMap<String, Object> implements Cloneable {
++
++    private transient Object bean;
++
++    private transient HashMap<String, Method> readMethods = new HashMap<String, Method>();
++    private transient HashMap<String, Method> writeMethods = new HashMap<String, Method>();
++    private transient HashMap<String, Class> types = new HashMap<String, Class>();
++
++    /**
++     * An empty array.  Used to invoke accessors via reflection.
++     */
++    public static final Object[] NULL_ARGUMENTS = {};
++
++    /**
++     * Maps primitive Class types to transformers.  The transformer
++     * transform strings into the appropriate primitive wrapper.
++     */
++    public static HashMap defaultTransformers = new HashMap();
++
++    static {
++        defaultTransformers.put(Boolean.TYPE, new Transformer() {
++            public Object transform(Object input) {
++                return Boolean.valueOf(input.toString());
++            }
++        });
++        defaultTransformers.put(Character.TYPE, new Transformer() {
++            public Object transform(Object input) {
++                return new Character(input.toString().charAt(0));
++            }
++        });
++        defaultTransformers.put(Byte.TYPE, new Transformer() {
++            public Object transform(Object input) {
++                return Byte.valueOf(input.toString());
++            }
++        });
++        defaultTransformers.put(Short.TYPE, new Transformer() {
++            public Object transform(Object input) {
++                return Short.valueOf(input.toString());
++            }
++        });
++        defaultTransformers.put(Integer.TYPE, new Transformer() {
++            public Object transform(Object input) {
++                return Integer.valueOf(input.toString());
++            }
++        });
++        defaultTransformers.put(Long.TYPE, new Transformer() {
++            public Object transform(Object input) {
++                return Long.valueOf(input.toString());
++            }
++        });
++        defaultTransformers.put(Float.TYPE, new Transformer() {
++            public Object transform(Object input) {
++                return Float.valueOf(input.toString());
++            }
++        });
++        defaultTransformers.put(Double.TYPE, new Transformer() {
++            public Object transform(Object input) {
++                return Double.valueOf(input.toString());
++            }
++        });
++    }
++
++
++    // Constructors
++    //-------------------------------------------------------------------------
++
++    /**
++     * Constructs a new empty <code>BeanMap</code>.
++     */
++    public BeanMap() {
++    }
++
++    /**
++     * Constructs a new <code>BeanMap</code> that operates on the
++     * specified bean.  If the given bean is <code>null</code>, then
++     * this map will be empty.
++     *
++     * @param bean the bean for this map to operate on
++     */
++    public BeanMap(Object bean) {
++        this.bean = bean;
++        initialise();
++    }
++
++    // Map interface
++    //-------------------------------------------------------------------------
++
++    public String toString() {
++        return "BeanMap<" + String.valueOf(bean) + ">";
++    }
++
++    /**
++     * Clone this bean map using the following process:
++     * <p/>
++     * <ul>
++     * <li>If there is no underlying bean, return a cloned BeanMap without a
++     * bean.
++     * <p/>
++     * <li>Since there is an underlying bean, try to instantiate a new bean of
++     * the same type using Class.newInstance().
++     * <p/>
++     * <li>If the instantiation fails, throw a CloneNotSupportedException
++     * <p/>
++     * <li>Clone the bean map and set the newly instantiated bean as the
++     * underlying bean for the bean map.
++     * <p/>
++     * <li>Copy each property that is both readable and writable from the
++     * existing object to a cloned bean map.
++     * <p/>
++     * <li>If anything fails along the way, throw a
++     * CloneNotSupportedException.
++     * <p/>
++     * <ul>
++     */
++    public Object clone() throws CloneNotSupportedException {
++        BeanMap newMap = (BeanMap) super.clone();
++
++        if (bean == null) {
++            // no bean, just an empty bean map at the moment.  return a newly
++            // cloned and empty bean map.
++            return newMap;
++        }
++
++        Object newBean = null;
++        Class beanClass = null;
++        try {
++            beanClass = bean.getClass();
++            newBean = beanClass.newInstance();
++        } catch (Exception e) {
++            // unable to instantiate
++            throw new CloneNotSupportedException("Unable to instantiate the underlying bean \"" + beanClass.getName() + "\": " + e);
++        }
++
++        try {
++            newMap.setBean(newBean);
++        } catch (Exception exception) {
++            throw new CloneNotSupportedException("Unable to set bean in the cloned bean map: " + exception);
++        }
++
++        try {
++            // copy only properties that are readable and writable.  If its
++            // not readable, we can't get the value from the old map.  If
++            // its not writable, we can't write a value into the new map.
++            Iterator<String> readableKeys = readMethods.keySet().iterator();
++            while (readableKeys.hasNext()) {
++                String key = readableKeys.next();
++                if (getWriteMethod(key) != null) {
++                    newMap.put(key, get(key));
++                }
++            }
++        } catch (Exception exception) {
++            throw new CloneNotSupportedException("Unable to copy bean values to cloned bean map: " + exception);
++        }
++
++        return newMap;
++    }
++
++    /**
++     * Puts all of the writable properties from the given BeanMap into this
++     * BeanMap. Read-only and Write-only properties will be ignored.
++     *
++     * @param map the BeanMap whose properties to put
++     */
++    public void putAllWriteable(BeanMap map) {
++        Iterator<String> readableKeys = map.readMethods.keySet().iterator();
++        while (readableKeys.hasNext()) {
++            String key = readableKeys.next();
++            if (getWriteMethod(key) != null) {
++                this.put(key, map.get(key));
++            }
++        }
++    }
++
++
++    /**
++     * This method reinitializes the bean map to have default values for the
++     * bean's properties.  This is accomplished by constructing a new instance
++     * of the bean which the map uses as its underlying data source.  This
++     * behavior for <code>clear()</code> differs from the Map contract in that
++     * the mappings are not actually removed from the map (the mappings for a
++     * BeanMap are fixed).
++     */
++    public void clear() {
++        if (bean == null) return;
++
++        Class beanClass = null;
++        try {
++            beanClass = bean.getClass();
++            bean = beanClass.newInstance();
++        } catch (Exception e) {
++            throw new UnsupportedOperationException("Could not create new instance of class: " + beanClass);
++        }
++    }
++
++    /**
++     * Returns true if the bean defines a property with the given name.
++     * <p/>
++     * The given name must be a <code>String</code>; if not, this method
++     * returns false. This method will also return false if the bean
++     * does not define a property with that name.
++     * <p/>
++     * Write-only properties will not be matched as the test operates against
++     * property read methods.
++     *
++     * @param name the name of the property to check
++     * @return false if the given name is null or is not a <code>String</code>;
++     *         false if the bean does not define a property with that name; or
++     *         true if the bean does define a property with that name
++     */
++    public boolean containsKey(String name) {
++        Method method = getReadMethod(name);
++        return method != null;
++    }
++
++    /**
++     * Returns true if the bean defines a property whose current value is
++     * the given object.
++     *
++     * @param value the value to check
++     * @return false  true if the bean has at least one property whose
++     *         current value is that object, false otherwise
++     */
++    public boolean containsValue(Object value) {
++        // use default implementation
++        return super.containsValue(value);
++    }
++
++    /**
++     * Returns the value of the bean's property with the given name.
++     * <p/>
++     * The given name must be a {@link String} and must not be
++     * null; otherwise, this method returns <code>null</code>.
++     * If the bean defines a property with the given name, the value of
++     * that property is returned.  Otherwise, <code>null</code> is
++     * returned.
++     * <p/>
++     * Write-only properties will not be matched as the test operates against
++     * property read methods.
++     *
++     * @param name the name of the property whose value to return
++     * @return the value of the property with that name
++     */
++    public Object get(String name) {
++        if (bean != null) {
++            Method method = getReadMethod(name);
++            if (method != null) {
++                try {
++                    return method.invoke(bean, NULL_ARGUMENTS);
++                } catch (IllegalAccessException e) {
++                    logWarn(e);
++                } catch (IllegalArgumentException e) {
++                    logWarn(e);
++                } catch (InvocationTargetException e) {
++                    logWarn(e);
++                } catch (NullPointerException e) {
++                    logWarn(e);
++                }
++            }
++        }
++        return null;
++    }
++
++    /**
++     * Sets the bean property with the given name to the given value.
++     *
++     * @param name  the name of the property to set
++     * @param value the value to set that property to
++     * @return the previous value of that property
++     * @throws IllegalArgumentException if the given name is null;
++     *                                  if the given name is not a {@link String}; if the bean doesn't
++     *                                  define a property with that name; or if the bean property with
++     *                                  that name is read-only
++     */
++    public Object put(String name, Object value) throws IllegalArgumentException, ClassCastException {
++        if (bean != null) {
++            Object oldValue = get(name);
++            Method method = getWriteMethod(name);
++            if (method == null) {
++                throw new IllegalArgumentException("The bean of type: " + bean.getClass().getName() + " has no property called: " + name);
++            }
++            try {
++                Object[] arguments = createWriteMethodArguments(method, value);
++                method.invoke(bean, arguments);
++
++                Object newValue = get(name);
++                firePropertyChange(name, oldValue, newValue);
++            } catch (InvocationTargetException e) {
++                logInfo(e);
++                throw new IllegalArgumentException(e.getMessage());
++            } catch (IllegalAccessException e) {
++                logInfo(e);
++                throw new IllegalArgumentException(e.getMessage());
++            }
++            return oldValue;
++        }
++        return null;
++    }
++
++    /**
++     * Returns the number of properties defined by the bean.
++     *
++     * @return the number of properties defined by the bean
++     */
++    public int size() {
++        return readMethods.size();
++    }
++
++
++    /**
++     * Get the keys for this BeanMap.
++     * <p/>
++     * Write-only properties are <b>not</b> included in the returned set of
++     * property names, although it is possible to set their value and to get
++     * their type.
++     *
++     * @return BeanMap keys.  The Set returned by this method is not
++     *         modifiable.
++     */
++    public Set<String> keySet() {
++        return UnmodifiableSet.decorate(readMethods.keySet());
++    }
++
++    /**
++     * Gets a Set of MapEntry objects that are the mappings for this BeanMap.
++     * <p/>
++     * Each MapEntry can be set but not removed.
++     *
++     * @return the unmodifiable set of mappings
++     */
++    public Set<Entry<String, Object>> entrySet() {
++        return UnmodifiableSet.decorate(new AbstractSet<Entry<String, Object>>() {
++            public Iterator<Entry<String, Object>> iterator() {
++                return entryIterator();
++            }
++
++            public int size() {
++                return BeanMap.this.readMethods.size();
++            }
++        });
++    }
++
++    /**
++     * Returns the values for the BeanMap.
++     *
++     * @return values for the BeanMap.  The returned collection is not
++     *         modifiable.
++     */
++    public Collection<Object> values() {
++        ArrayList answer = new ArrayList(readMethods.size());
++        for (Iterator iter = valueIterator(); iter.hasNext();) {
++            answer.add(iter.next());
++        }
++        return UnmodifiableList.decorate(answer);
++    }
++
++
++    // Helper methods
++    //-------------------------------------------------------------------------
++
++    /**
++     * Returns the type of the property with the given name.
++     *
++     * @param name the name of the property
++     * @return the type of the property, or <code>null</code> if no such
++     *         property exists
++     */
++    public Class getType(String name) {
++        return (Class) types.get(name);
++    }
++
++    /**
++     * Convenience method for getting an iterator over the keys.
++     * <p/>
++     * Write-only properties will not be returned in the iterator.
++     *
++     * @return an iterator over the keys
++     */
++    public Iterator<String> keyIterator() {
++        return readMethods.keySet().iterator();
++    }
++
++    /**
++     * Convenience method for getting an iterator over the values.
++     *
++     * @return an iterator over the values
++     */
++    public Iterator<Object> valueIterator() {
++        final Iterator<String> iter = keyIterator();
++        return new Iterator<Object>() {
++            public boolean hasNext() {
++                return iter.hasNext();
++            }
++
++            public Object next() {
++                Object key = iter.next();
++                return get(key);
++            }
++
++            public void remove() {
++                throw new UnsupportedOperationException("remove() not supported for BeanMap");
++            }
++        };
++    }
++
++    /**
++     * Convenience method for getting an iterator over the entries.
++     *
++     * @return an iterator over the entries
++     */
++    public Iterator<Entry<String, Object>> entryIterator() {
++        final Iterator<String> iter = keyIterator();
++        return new Iterator<Entry<String, Object>>() {
++            public boolean hasNext() {
++                return iter.hasNext();
++            }
++
++            public Entry<String, Object> next() {
++                String key = iter.next();
++                Object value = get(key);
++                return new MyMapEntry(BeanMap.this, key, value);
++            }
++
++            public void remove() {
++                throw new UnsupportedOperationException("remove() not supported for BeanMap");
++            }
++        };
++    }
++
++
++    // Properties
++    //-------------------------------------------------------------------------
++
++    /**
++     * Returns the bean currently being operated on.  The return value may
++     * be null if this map is empty.
++     *
++     * @return the bean being operated on by this map
++     */
++    public Object getBean() {
++        return bean;
++    }
++
++    /**
++     * Sets the bean to be operated on by this map.  The given value may
++     * be null, in which case this map will be empty.
++     *
++     * @param newBean the new bean to operate on
++     */
++    public void setBean(Object newBean) {
++        bean = newBean;
++        reinitialise();
++    }
++
++    /**
++     * Returns the accessor for the property with the given name.
++     *
++     * @param name the name of the property
++     * @return the accessor method for the property, or null
++     */
++    public Method getReadMethod(String name) {
++        return readMethods.get(name);
++    }
++
++    /**
++     * Returns the mutator for the property with the given name.
++     *
++     * @param name the name of the property
++     * @return the mutator method for the property, or null
++     */
++    public Method getWriteMethod(String name) {
++        return (Method) writeMethods.get(name);
++    }
++
++
++    // Implementation methods
++    //-------------------------------------------------------------------------
++
++    /**
++     * Reinitializes this bean.  Called during {@link #setBean(Object)}.
++     * Does introspection to find properties.
++     */
++    protected void reinitialise() {
++        readMethods.clear();
++        writeMethods.clear();
++        types.clear();
++        initialise();
++    }
++
++    private void initialise() {
++        if (getBean() == null) return;
++
++        Class beanClass = getBean().getClass();
++        try {
++            //BeanInfo beanInfo = Introspector.getBeanInfo( bean, null );
++            BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
++            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
++            if (propertyDescriptors != null) {
++                for (int i = 0; i < propertyDescriptors.length; i++) {
++                    PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
++                    if (propertyDescriptor != null) {
++                        String name = propertyDescriptor.getName();
++                        Method readMethod = propertyDescriptor.getReadMethod();
++                        Method writeMethod = propertyDescriptor.getWriteMethod();
++                        Class aType = propertyDescriptor.getPropertyType();
++
++                        if (readMethod != null) {
++                            readMethods.put(name, readMethod);
++                        }
++                        if (writeMethods != null) {
++                            writeMethods.put(name, writeMethod);
++                        }
++                        types.put(name, aType);
++                    }
++                }
++            }
++        } catch (IntrospectionException e) {
++            logWarn(e);
++        }
++    }
++
++    /**
++     * Called during a successful {@link #put(Object,Object)} operation.
++     * Default implementation does nothing.  Override to be notified of
++     * property changes in the bean caused by this map.
++     *
++     * @param key      the name of the property that changed
++     * @param oldValue the old value for that property
++     * @param newValue the new value for that property
++     */
++    protected void firePropertyChange(String key, Object oldValue, Object newValue) {
++    }
++
++    // Implementation classes
++    //-------------------------------------------------------------------------
++
++    /**
++     * Map entry used by {@link BeanMap}.
++     */
++    protected static class MyMapEntry extends AbstractMapEntry<String, Object> {
++        private BeanMap owner;
++
++        /**
++         * Constructs a new <code>MyMapEntry</code>.
++         *
++         * @param owner the BeanMap this entry belongs to
++         * @param key   the key for this entry
++         * @param value the value for this entry
++         */
++        protected MyMapEntry(BeanMap owner, String key, Object value) {
++            super(key, value);
++            this.owner = owner;
++        }
++
++        /**
++         * Sets the value.
++         *
++         * @param value the new value for the entry
++         * @return the old value for the entry
++         */
++        public Object setValue(Object value) {
++            String key = getKey();
++            Object oldValue = owner.get(key);
++
++            owner.put(key, value);
++            Object newValue = owner.get(key);
++            super.setValue(newValue);
++            return oldValue;
++        }
++    }
++
++    /**
++     * Creates an array of parameters to pass to the given mutator method.
++     * If the given object is not the right type to pass to the method
++     * directly, it will be converted using {@link #convertType(Class,Object)}.
++     *
++     * @param method the mutator method
++     * @param value  the value to pass to the mutator method
++     * @return an array containing one object that is either the given value
++     *         or a transformed value
++     * @throws IllegalAccessException   if {@link #convertType(Class,Object)}
++     *                                  raises it
++     * @throws IllegalArgumentException if any other exception is raised
++     *                                  by {@link #convertType(Class,Object)}
++     */
++    protected Object[] createWriteMethodArguments(Method method, Object value) throws IllegalAccessException, ClassCastException {
++        try {
++            if (value != null) {
++                Class[] types = method.getParameterTypes();
++                if (types != null && types.length > 0) {
++                    Class paramType = types[0];
++                    if (!paramType.isAssignableFrom(value.getClass())) {
++                        value = convertType(paramType, value);
++                    }
++                }
++            }
++            Object[] answer = {value};
++            return answer;
++        } catch (InvocationTargetException e) {
++            logInfo(e);
++            throw new IllegalArgumentException(e.getMessage());
++        } catch (InstantiationException e) {
++            logInfo(e);
++            throw new IllegalArgumentException(e.getMessage());
++        }
++    }
++
++    /**
++     * Converts the given value to the given type.  First, reflection is
++     * is used to find a public constructor declared by the given class
++     * that takes one argument, which must be the precise type of the
++     * given value.  If such a constructor is found, a new object is
++     * created by passing the given value to that constructor, and the
++     * newly constructed object is returned.<P>
++     * <p/>
++     * If no such constructor exists, and the given type is a primitive
++     * type, then the given value is converted to a string using its
++     * {@link Object#toString() toString()} method, and that string is
++     * parsed into the correct primitive type using, for instance,
++     * {@link Integer#valueOf(String)} to convert the string into an
++     * <code>int</code>.<P>
++     * <p/>
++     * If no special constructor exists and the given type is not a
++     * primitive type, this method returns the original value.
++     *
++     * @param newType the type to convert the value to
++     * @param value   the value to convert
++     * @return the converted value
++     * @throws NumberFormatException     if newType is a primitive type, and
++     *                                   the string representation of the given value cannot be converted
++     *                                   to that type
++     * @throws InstantiationException    if the constructor found with
++     *                                   reflection raises it
++     * @throws InvocationTargetException if the constructor found with
++     *                                   reflection raises it
++     * @throws IllegalAccessException    never
++     * @throws IllegalArgumentException  never
++     */
++    protected Object convertType(Class newType, Object value) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
++
++        // try call constructor
++        Class[] types = {value.getClass()};
++        try {
++            Constructor constructor = newType.getConstructor(types);
++            Object[] arguments = {value};
++            return constructor.newInstance(arguments);
++        } catch (NoSuchMethodException e) {
++            // try using the transformers
++            Transformer transformer = getTypeTransformer(newType);
++            if (transformer != null) {
++                return transformer.transform(value);
++            }
++            return value;
++        }
++    }
++
++    /**
++     * Returns a transformer for the given primitive type.
++     *
++     * @param aType the primitive type whose transformer to return
++     * @return a transformer that will convert strings into that type,
++     *         or null if the given type is not a primitive type
++     */
++    protected Transformer getTypeTransformer(Class aType) {
++        return (Transformer) defaultTransformers.get(aType);
++    }
++
++    /**
++     * Logs the given exception to <code>System.out</code>.  Used to display
++     * warnings while accessing/mutating the bean.
++     *
++     * @param ex the exception to log
++     */
++    protected void logInfo(Exception ex) {
++        // Deliberately do not use LOG4J or Commons Logging to avoid dependencies
++        System.out.println("INFO: Exception: " + ex);
++    }
++
++    /**
++     * Logs the given exception to <code>System.err</code>.  Used to display
++     * errors while accessing/mutating the bean.
++     *
++     * @param ex the exception to log
++     */
++    protected void logWarn(Exception ex) {
++        // Deliberately do not use LOG4J or Commons Logging to avoid dependencies
++        System.out.println("WARN: Exception: " + ex);
++        ex.printStackTrace();
++    }
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/BidiMap.java
+@@ -0,0 +1,161 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.Set;
++
++/**
++ * Defines a map that allows bidirectional lookup between key and values.
++ * <p/>
++ * This extended <code>Map</code> represents a mapping where a key may
++ * lookup a value and a value may lookup a key with equal ease.
++ * This interface extends <code>Map</code> and so may be used anywhere a map
++ * is required. The interface provides an inverse map view, enabling
++ * full access to both directions of the <code>BidiMap</code>.
++ * <p/>
++ * Implementations should allow a value to be looked up from a key and
++ * a key to be looked up from a value with equal performance.
++ * <p/>
++ * This map enforces the restriction that there is a 1:1 relation between
++ * keys and values, meaning that multiple keys cannot map to the same value.
++ * This is required so that "inverting" the map results in a map without
++ * duplicate keys. See the {@link #put} method description for more information.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface BidiMap <K,V> extends IterableMap<K, V> {
++
++    /**
++     * Obtains a <code>MapIterator</code> over the map.
++     * <p/>
++     * A map iterator is an efficient way of iterating over maps.
++     * It does not require that the map is stored using Map Entry objects
++     * which can increase performance.
++     * <pre>
++     * BidiMap map = new DualHashBidiMap();
++     * MapIterator it = map.mapIterator();
++     * while (it.hasNext()) {
++     *   Object key = it.next();
++     *   Object value = it.getValue();
++     *   it.setValue("newValue");
++     * }
++     * </pre>
++     *
++     * @return a map iterator
++     */
++    MapIterator<K, V> mapIterator();
++
++    /**
++     * Puts the key-value pair into the map, replacing any previous pair.
++     * <p/>
++     * When adding a key-value pair, the value may already exist in the map
++     * against a different key. That mapping is removed, to ensure that the
++     * value only occurs once in the inverse map.
++     * <pre>
++     *  BidiMap map1 = new DualHashBidiMap();
++     *  map.put("A","B");  // contains A mapped to B, as per Map
++     *  map.put("A","C");  // contains A mapped to C, as per Map
++     * <p/>
++     *  BidiMap map2 = new DualHashBidiMap();
++     *  map.put("A","B");  // contains A mapped to B, as per Map
++     *  map.put("C","B");  // contains C mapped to B, key A is removed
++     * </pre>
++     *
++     * @param key   the key to store
++     * @param value the value to store
++     * @return the previous value mapped to this key
++     * @throws UnsupportedOperationException if the <code>put</code> method is not supported
++     * @throws ClassCastException            (optional) if the map limits the type of the
++     *                                       value and the specified value is inappropriate
++     * @throws IllegalArgumentException      (optional) if the map limits the values
++     *                                       in some way and the value was invalid
++     * @throws NullPointerException          (optional) if the map limits the values to
++     *                                       non-null and null was specified
++     */
++    V put(K key, V value);
++
++    /**
++     * Gets the key that is currently mapped to the specified value.
++     * <p/>
++     * If the value is not contained in the map, <code>null</code> is returned.
++     * <p/>
++     * Implementations should seek to make this method perform equally as well
++     * as <code>get(Object)</code>.
++     *
++     * @param value the value to find the key for
++     * @return the mapped key, or <code>null</code> if not found
++     * @throws ClassCastException   (optional) if the map limits the type of the
++     *                              value and the specified value is inappropriate
++     * @throws NullPointerException (optional) if the map limits the values to
++     *                              non-null and null was specified
++     */
++    K getKey(Object value);
++
++    /**
++     * Removes the key-value pair that is currently mapped to the specified
++     * value (optional operation).
++     * <p/>
++     * If the value is not contained in the map, <code>null</code> is returned.
++     * <p/>
++     * Implementations should seek to make this method perform equally as well
++     * as <code>remove(Object)</code>.
++     *
++     * @param value the value to find the key-value pair for
++     * @return the key that was removed, <code>null</code> if nothing removed
++     * @throws ClassCastException            (optional) if the map limits the type of the
++     *                                       value and the specified value is inappropriate
++     * @throws NullPointerException          (optional) if the map limits the values to
++     *                                       non-null and null was specified
++     * @throws UnsupportedOperationException if this method is not supported
++     *                                       by the implementation
++     */
++    K removeValue(Object value);
++
++    /**
++     * Gets a view of this map where the keys and values are reversed.
++     * <p/>
++     * Changes to one map will be visible in the other and vice versa.
++     * This enables both directions of the map to be accessed as a <code>Map</code>.
++     * <p/>
++     * Implementations should seek to avoid creating a new object every time this
++     * method is called. See <code>AbstractMap.values()</code> etc. Calling this
++     * method on the inverse map should return the original.
++     *
++     * @return an inverted bidirectional map
++     */
++    BidiMap<V, K> inverseBidiMap();
++
++
++    /**
++     * Returns a set view of the values contained in this BidiMap.  The
++     * set is backed by the map, so changes to the map are reflected in
++     * the collection, and vice-versa.  If the map is modified while an
++     * iteration over the collection is in progress (except through the
++     * iterator's own <tt>remove</tt> operation), the results of the
++     * iteration are undefined.  The collection supports element removal,
++     * which removes the corresponding mapping from the map, via the
++     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
++     * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt> operations.
++     * It does not support the add or <tt>addAll</tt> operations.
++     *
++     * @return a Set view of the values contained in this map.
++     */
++    Set<V> values();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/BoundedCollection.java
+@@ -0,0 +1,51 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.Collection;
++
++/**
++ * Defines a collection that is bounded in size.
++ * <p/>
++ * The size of the collection can vary, but it can never exceed a preset
++ * maximum number of elements. This interface allows the querying of details
++ * associated with the maximum number of elements.
++ *
++ * @author Matt Hall, John Watkinson, Herve Quiroz
++ * @author Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @see CollectionUtils#isFull
++ * @see CollectionUtils#maxSize
++ * @since Commons Collections 3.0
++ */
++public interface BoundedCollection <E> extends Collection<E> {
++
++    /**
++     * Returns true if this collection is full and no new elements can be added.
++     *
++     * @return <code>true</code> if the collection is full
++     */
++    boolean isFull();
++
++    /**
++     * Gets the maximum size of the collection (the bound).
++     *
++     * @return the maximum number of elements the collection can hold
++     */
++    int maxSize();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/BoundedMap.java
+@@ -0,0 +1,48 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.Map;
++
++/**
++ * Defines a map that is bounded in size.
++ * <p/>
++ * The size of the map can vary, but it can never exceed a preset
++ * maximum number of elements. This interface allows the querying of details
++ * associated with the maximum number of elements.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface BoundedMap <K,V> extends Map<K, V> {
++
++    /**
++     * Returns true if this map is full and no new elements can be added.
++     *
++     * @return <code>true</code> if the map is full
++     */
++    boolean isFull();
++
++    /**
++     * Gets the maximum size of the map (the bound).
++     *
++     * @return the maximum number of elements the map can hold
++     */
++    int maxSize();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/Buffer.java
+@@ -0,0 +1,63 @@
++// // GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.Collection;
++
++/**
++ * Defines a collection that allows objects to be removed in some well-defined order.
++ * <p/>
++ * The removal order can be based on insertion order (eg, a FIFO queue or a
++ * LIFO stack), on access order (eg, an LRU cache), on some arbitrary comparator
++ * (eg, a priority queue) or on any other well-defined ordering.
++ * <p/>
++ * Note that the removal order is not necessarily the same as the iteration
++ * order.  A <code>Buffer</code> implementation may have equivalent removal
++ * and iteration orders, but this is not required.
++ * <p/>
++ * This interface does not specify any behavior for
++ * {@link Object#equals(Object)} and {@link Object#hashCode} methods.  It
++ * is therefore possible for a <code>Buffer</code> implementation to also
++ * also implement {@link java.util.List}, {@link java.util.Set} or
++ * {@link Bag}.
++ *
++ * @author Avalon
++ * @author Berin Loritsch
++ * @author Paul Jack
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.1
++ */
++public interface Buffer <E> extends Collection<E> {
++
++    /**
++     * Gets and removes the next object from the buffer.
++     *
++     * @return the next object in the buffer, which is also removed
++     * @throws BufferUnderflowException if the buffer is already empty
++     */
++    E remove();
++
++    /**
++     * Gets the next object from the buffer without removing it.
++     *
++     * @return the next object in the buffer, which is not removed
++     * @throws BufferUnderflowException if the buffer is empty
++     */
++    E get();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/BufferOverflowException.java
+@@ -0,0 +1,75 @@
++// GenericsNote: No conversion needed.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++/**
++ * The BufferOverflowException is used when the buffer's capacity has been
++ * exceeded.
++ *
++ * @author Avalon
++ * @author <a href="mailto:bloritsch at apache.org">Berin Loritsch</a>
++ * @author <a href="mailto:jefft at apache.org">Jeff Turner</a>
++ * @author Paul Jack
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.1
++ */
++public class BufferOverflowException extends RuntimeException {
++
++    /**
++     * The root cause throwable
++     */
++    private final Throwable throwable;
++
++    /**
++     * Constructs a new <code>BufferOverflowException</code>.
++     */
++    public BufferOverflowException() {
++        super();
++        throwable = null;
++    }
++
++    /**
++     * Construct a new <code>BufferOverflowException</code>.
++     *
++     * @param message the detail message for this exception
++     */
++    public BufferOverflowException(String message) {
++        this(message, null);
++    }
++
++    /**
++     * Construct a new <code>BufferOverflowException</code>.
++     *
++     * @param message   the detail message for this exception
++     * @param exception the root cause of the exception
++     */
++    public BufferOverflowException(String message, Throwable exception) {
++        super(message);
++        throwable = exception;
++    }
++
++    /**
++     * Gets the root cause of the exception.
++     *
++     * @return the root cause
++     */
++    public final Throwable getCause() {
++        return throwable;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/BufferUnderflowException.java
+@@ -0,0 +1,78 @@
++// GenericsNote: No conversion necessary.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.NoSuchElementException;
++
++/**
++ * The BufferUnderflowException is used when the buffer is already empty.
++ * <p/>
++ * NOTE: From version 3.0, this exception extends NoSuchElementException.
++ *
++ * @author Avalon
++ * @author Berin Loritsch
++ * @author Jeff Turner
++ * @author Paul Jack
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.1
++ */
++public class BufferUnderflowException extends NoSuchElementException {
++
++    /**
++     * The root cause throwable
++     */
++    private final Throwable throwable;
++
++    /**
++     * Constructs a new <code>BufferUnderflowException</code>.
++     */
++    public BufferUnderflowException() {
++        super();
++        throwable = null;
++    }
++
++    /**
++     * Construct a new <code>BufferUnderflowException</code>.
++     *
++     * @param message the detail message for this exception
++     */
++    public BufferUnderflowException(String message) {
++        this(message, null);
++    }
++
++    /**
++     * Construct a new <code>BufferUnderflowException</code>.
++     *
++     * @param message   the detail message for this exception
++     * @param exception the root cause of the exception
++     */
++    public BufferUnderflowException(String message, Throwable exception) {
++        super(message);
++        throwable = exception;
++    }
++
++    /**
++     * Gets the root cause of the exception.
++     *
++     * @return the root cause
++     */
++    public final Throwable getCause() {
++        return throwable;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/BufferUtils.java
+@@ -0,0 +1,142 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.buffer.*;
++
++/**
++ * Provides utility methods and decorators for {@link Buffer} instances.
++ *
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @author Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.1
++ */
++public class BufferUtils {
++
++    /**
++     * An empty unmodifiable buffer.
++     */
++    public static final Buffer EMPTY_BUFFER = UnmodifiableBuffer.decorate(new ArrayStack(1));
++
++    /**
++     * <code>BufferUtils</code> should not normally be instantiated.
++     */
++    public BufferUtils() {
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a synchronized buffer backed by the given buffer.
++     * Much like the synchronized collections15 returned by
++     * {@link java.util.Collections}, you must manually synchronize on
++     * the returned buffer's iterator to avoid non-deterministic behavior:
++     * <p/>
++     * <pre>
++     * Buffer b = BufferUtils.synchronizedBuffer(myBuffer);
++     * synchronized (b) {
++     *     Iterator i = b.iterator();
++     *     while (i.hasNext()) {
++     *         process (i.next());
++     *     }
++     * }
++     * </pre>
++     *
++     * @param buffer the buffer to synchronize, must not be null
++     * @return a synchronized buffer backed by that buffer
++     * @throws IllegalArgumentException if the Buffer is null
++     */
++    public static <E> Buffer<E> synchronizedBuffer(Buffer<E> buffer) {
++        return SynchronizedBuffer.decorate(buffer);
++    }
++
++    /**
++     * Returns a synchronized buffer backed by the given buffer that will
++     * block on {@link Buffer#get()} and {@link Buffer#remove()} operations.
++     * If the buffer is empty, then the {@link Buffer#get()} and
++     * {@link Buffer#remove()} operations will block until new elements
++     * are added to the buffer, rather than immediately throwing a
++     * <code>BufferUnderflowException</code>.
++     *
++     * @param buffer the buffer to synchronize, must not be null
++     * @return a blocking buffer backed by that buffer
++     * @throws IllegalArgumentException if the Buffer is null
++     */
++    public static <E> Buffer<E> blockingBuffer(Buffer<E> buffer) {
++        return BlockingBuffer.decorate(buffer);
++    }
++
++    /**
++     * Returns an unmodifiable buffer backed by the given buffer.
++     *
++     * @param buffer the buffer to make unmodifiable, must not be null
++     * @return an unmodifiable buffer backed by that buffer
++     * @throws IllegalArgumentException if the Buffer is null
++     */
++    public static <E> Buffer<E> unmodifiableBuffer(Buffer<E> buffer) {
++        return UnmodifiableBuffer.decorate(buffer);
++    }
++
++    /**
++     * Returns a predicated (validating) buffer backed by the given buffer.
++     * <p/>
++     * Only objects that pass the test in the given predicate can be added to the buffer.
++     * Trying to add an invalid object results in an IllegalArgumentException.
++     * It is important not to use the original buffer after invoking this method,
++     * as it is a backdoor for adding invalid objects.
++     *
++     * @param buffer    the buffer to predicate, must not be null
++     * @param predicate the predicate used to evaluate new elements, must not be null
++     * @return a predicated buffer
++     * @throws IllegalArgumentException if the Buffer or Predicate is null
++     */
++    public static <E> Buffer<E> predicatedBuffer(Buffer<E> buffer, Predicate<E> predicate) {
++        return PredicatedBuffer.decorate(buffer, predicate);
++    }
++
++    /**
++     * Returns a typed buffer backed by the given buffer.
++     * <p/>
++     * Only elements of the specified type can be added to the buffer.
++     *
++     * @param buffer the buffer to predicate, must not be null
++     * @param type   the type to allow into the buffer, must not be null
++     * @return a typed buffer
++     * @throws IllegalArgumentException if the buffer or type is null
++     * @deprecated No longer required with Java 1.5 Generics.
++     */
++    public static <E> Buffer<E> typedBuffer(Buffer<E> buffer, Class<E> type) {
++        return TypedBuffer.decorate(buffer, type);
++    }
++
++    /**
++     * Returns a transformed buffer backed by the given buffer.
++     * <p/>
++     * Each object is passed through the transformer as it is added to the
++     * Buffer. It is important not to use the original buffer after invoking this
++     * method, as it is a backdoor for adding untransformed objects.
++     *
++     * @param buffer      the buffer to predicate, must not be null
++     * @param transformer the transformer for the buffer, must not be null
++     * @return a transformed buffer backed by the given buffer
++     * @throws IllegalArgumentException if the Buffer or Transformer is null
++     */
++    public static <I,O> Buffer<O> transformedBuffer(Buffer<I> buffer, Transformer<I, O> transformer) {
++        return TransformedBuffer.decorate(buffer, transformer);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/Closure.java
+@@ -0,0 +1,46 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++/**
++ * Defines a functor interface implemented by classes that do something.
++ * <p/>
++ * A <code>Closure</code> represents a block of code which is executed from
++ * inside some block, function or iteration. It operates an input object.
++ * <p/>
++ * Standard implementations of common closures are provided by
++ * {@link ClosureUtils}. These include method invokation and for/while loops.
++ *
++ * @author James Strachan
++ * @author Nicola Ken Barozzi
++ * @author Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 1.0
++ */
++public interface Closure <T> {
++
++    /**
++     * Performs an action on the specified input object.
++     *
++     * @param input the input to execute on
++     * @throws ClassCastException       (runtime) if the input is the wrong class
++     * @throws IllegalArgumentException (runtime) if the input is invalid
++     * @throws FunctorException         (runtime) if any other error occurs
++     */
++    public void execute(T input);
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/ClosureUtils.java
+@@ -0,0 +1,326 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.functors.*;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Map;
++
++/**
++ * <code>ClosureUtils</code> provides reference implementations and utilities
++ * for the Closure functor interface. The supplied closures are:
++ * <ul>
++ * <li>Invoker - invokes a method on the input object
++ * <li>For - repeatedly calls a closure for a fixed number of times
++ * <li>While - repeatedly calls a closure while a predicate is true
++ * <li>DoWhile - repeatedly calls a closure while a predicate is true
++ * <li>Chained - chains two or more closures together
++ * <li>Switch - calls one closure based on one or more predicates
++ * <li>SwitchMap - calls one closure looked up from a Map
++ * <li>Transformer - wraps a Transformer as a Closure
++ * <li>NOP - does nothing
++ * <li>Exception - always throws an exception
++ * </ul>
++ * All the supplied closures are Serializable.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class ClosureUtils {
++
++    /**
++     * This class is not normally instantiated.
++     */
++    public ClosureUtils() {
++        super();
++    }
++
++    /**
++     * Gets a Closure that always throws an exception.
++     * This could be useful during testing as a placeholder.
++     *
++     * @return the closure
++     * @see org.apache.commons.collections15.functors.ExceptionClosure
++     */
++    public static Closure exceptionClosure() {
++        return ExceptionClosure.INSTANCE;
++    }
++
++    /**
++     * Gets a Closure that will do nothing.
++     * This could be useful during testing as a placeholder.
++     *
++     * @return the closure
++     * @see org.apache.commons.collections15.functors.NOPClosure
++     */
++    public static Closure nopClosure() {
++        return NOPClosure.INSTANCE;
++    }
++
++    /**
++     * Creates a Closure that calls a Transformer each time it is called.
++     * The transformer will be called using the closure's input object.
++     * The transformer's result will be ignored.
++     *
++     * @param transformer the transformer to run each time in the closure, null means nop
++     * @return the closure
++     * @see org.apache.commons.collections15.functors.TransformerClosure
++     */
++    public static <I,O> Closure<I> asClosure(Transformer<I, O> transformer) {
++        return TransformerClosure.getInstance(transformer);
++    }
++
++    /**
++     * Creates a Closure that will call the closure <code>count</code> times.
++     * <p/>
++     * A null closure or zero count returns the <code>NOPClosure</code>.
++     *
++     * @param count   the number of times to loop
++     * @param closure the closure to call repeatedly
++     * @return the <code>for</code> closure
++     * @see org.apache.commons.collections15.functors.ForClosure
++     */
++    public static <T> Closure<T> forClosure(int count, Closure<T> closure) {
++        return ForClosure.getInstance(count, closure);
++    }
++
++    /**
++     * Creates a Closure that will call the closure repeatedly until the
++     * predicate returns false.
++     *
++     * @param predicate the predicate to use as an end of loop test, not null
++     * @param closure   the closure to call repeatedly, not null
++     * @return the <code>while</code> closure
++     * @throws IllegalArgumentException if either argument is null
++     * @see org.apache.commons.collections15.functors.WhileClosure
++     */
++    public static <T> Closure<T> whileClosure(Predicate<? super T> predicate, Closure<? super T> closure) {
++        return WhileClosure.<T>getInstance(predicate, closure, false);
++    }
++
++    /**
++     * Creates a Closure that will call the closure once and then repeatedly
++     * until the predicate returns false.
++     *
++     * @param closure   the closure to call repeatedly, not null
++     * @param predicate the predicate to use as an end of loop test, not null
++     * @return the <code>do-while</code> closure
++     * @throws IllegalArgumentException if either argument is null
++     * @see org.apache.commons.collections15.functors.WhileClosure
++     */
++    public static <T> Closure<T> doWhileClosure(Closure<? super T> closure, Predicate<? super T> predicate) {
++        return WhileClosure.<T>getInstance(predicate, closure, true);
++    }
++
++    /**
++     * Creates a Closure that will invoke a specific method on the closure's
++     * input object by reflection.
++     *
++     * @param methodName the name of the method
++     * @return the <code>invoker</code> closure
++     * @throws IllegalArgumentException if the method name is null
++     * @see org.apache.commons.collections15.functors.InvokerTransformer
++     * @see org.apache.commons.collections15.functors.TransformerClosure
++     */
++    public static Closure invokerClosure(String methodName) {
++        // reuse transformer as it has caching - this is lazy really, should have inner class here
++        return asClosure(InvokerTransformer.getInstance(methodName));
++    }
++
++    /**
++     * Creates a Closure that will invoke a specific method on the closure's
++     * input object by reflection.
++     *
++     * @param methodName the name of the method
++     * @param paramTypes the parameter types
++     * @param args       the arguments
++     * @return the <code>invoker</code> closure
++     * @throws IllegalArgumentException if the method name is null
++     * @throws IllegalArgumentException if the paramTypes and args don't match
++     * @see org.apache.commons.collections15.functors.InvokerTransformer
++     * @see org.apache.commons.collections15.functors.TransformerClosure
++     */
++    public static Closure invokerClosure(String methodName, Class[] paramTypes, Object[] args) {
++        // reuse transformer as it has caching - this is lazy really, should have inner class here
++        return asClosure(InvokerTransformer.getInstance(methodName, paramTypes, args));
++    }
++
++    /**
++     * Create a new Closure that calls two Closures, passing the result of
++     * the first into the second.
++     *
++     * @param closure1 the first closure
++     * @param closure2 the second closure
++     * @return the <code>chained</code> closure
++     * @throws IllegalArgumentException if either closure is null
++     * @see org.apache.commons.collections15.functors.ChainedClosure
++     */
++    public static <T> Closure<T> chainedClosure(Closure<T> closure1, Closure<T> closure2) {
++        return ChainedClosure.<T>getInstance(closure1, closure2);
++    }
++
++    /**
++     * Create a new Closure that calls each closure in turn, passing the
++     * result into the next closure.
++     *
++     * @param closures an array of closures to chain
++     * @return the <code>chained</code> closure
++     * @throws IllegalArgumentException if the closures array is null
++     * @throws IllegalArgumentException if any closure in the array is null
++     * @see org.apache.commons.collections15.functors.ChainedClosure
++     */
++    public static <T> Closure<T> chainedClosure(Closure<T>[] closures) {
++        return ChainedClosure.getInstance(closures);
++    }
++
++    /**
++     * Create a new Closure that calls each closure in turn, passing the
++     * result into the next closure. The ordering is that of the iterator()
++     * method on the collection.
++     *
++     * @param closures a collection of closures to chain
++     * @return the <code>chained</code> closure
++     * @throws IllegalArgumentException if the closures collection is null
++     * @throws IllegalArgumentException if the closures collection is empty
++     * @throws IllegalArgumentException if any closure in the collection is null
++     * @see org.apache.commons.collections15.functors.ChainedClosure
++     */
++    public static <T> Closure<T> chainedClosure(Collection<T> closures) {
++        return ChainedClosure.getInstance(closures);
++    }
++
++    /**
++     * Create a new Closure that calls one of two closures depending
++     * on the specified predicate.
++     *
++     * @param predicate    the predicate to switch on
++     * @param trueClosure  the closure called if the predicate is true
++     * @param falseClosure the closure called if the predicate is false
++     * @return the <code>switch</code> closure
++     * @throws IllegalArgumentException if the predicate is null
++     * @throws IllegalArgumentException if either closure is null
++     * @see org.apache.commons.collections15.functors.IfClosure
++     */
++    public static <T> Closure<T> ifClosure(Predicate<? super T> predicate, Closure<? super T> trueClosure, Closure<? super T> falseClosure) {
++        return IfClosure.<T>getInstance(predicate, trueClosure, falseClosure);
++    }
++
++    /**
++     * Create a new Closure that calls one of the closures depending
++     * on the predicates.
++     * <p/>
++     * The closure at array location 0 is called if the predicate at array
++     * location 0 returned true. Each predicate is evaluated
++     * until one returns true.
++     *
++     * @param predicates an array of predicates to check, not null
++     * @param closures   an array of closures to call, not null
++     * @return the <code>switch</code> closure
++     * @throws IllegalArgumentException if the either array is null
++     * @throws IllegalArgumentException if any element in the arrays is null
++     * @throws IllegalArgumentException if the arrays are different sizes
++     * @see org.apache.commons.collections15.functors.SwitchClosure
++     */
++    public static <T> Closure<T> switchClosure(Predicate<? super T>[] predicates, Closure<? super T>[] closures) {
++        return SwitchClosure.<T>getInstance(predicates, closures, null);
++    }
++
++    /**
++     * Create a new Closure that calls one of the closures depending
++     * on the predicates.
++     * <p/>
++     * The closure at array location 0 is called if the predicate at array
++     * location 0 returned true. Each predicate is evaluated
++     * until one returns true. If no predicates evaluate to true, the default
++     * closure is called.
++     *
++     * @param predicates     an array of predicates to check, not null
++     * @param closures       an array of closures to call, not null
++     * @param defaultClosure the default to call if no predicate matches
++     * @return the <code>switch</code> closure
++     * @throws IllegalArgumentException if the either array is null
++     * @throws IllegalArgumentException if any element in the arrays is null
++     * @throws IllegalArgumentException if the arrays are different sizes
++     * @see org.apache.commons.collections15.functors.SwitchClosure
++     */
++    public static <T> Closure<T> switchClosure(Predicate<? super T>[] predicates, Closure<? super T>[] closures, Closure<? super T> defaultClosure) {
++        return SwitchClosure.<T>getInstance(predicates, closures, defaultClosure);
++    }
++
++    /**
++     * Create a new Closure that calls one of the closures depending
++     * on the predicates.
++     * <p/>
++     * The Map consists of Predicate keys and Closure values. A closure
++     * is called if its matching predicate returns true. Each predicate is evaluated
++     * until one returns true. If no predicates evaluate to true, the default
++     * closure is called. The default closure is set in the map with a
++     * null key. The ordering is that of the iterator() method on the entryset
++     * collection of the map.
++     *
++     * @param predicatesAndClosures a map of predicates to closures
++     * @return the <code>switch</code> closure
++     * @throws IllegalArgumentException if the map is null
++     * @throws IllegalArgumentException if the map is empty
++     * @throws IllegalArgumentException if any closure in the map is null
++     * @throws ClassCastException       if the map elements are of the wrong type
++     * @see org.apache.commons.collections15.functors.SwitchClosure
++     */
++    public static <T> Closure<T> switchClosure(Map<Predicate<? super T>, Closure<? super T>> predicatesAndClosures) {
++        return SwitchClosure.<T>getInstance(predicatesAndClosures);
++    }
++
++    /**
++     * Create a new Closure that uses the input object as a key to find the
++     * closure to call.
++     * <p/>
++     * The Map consists of object keys and Closure values. A closure
++     * is called if the input object equals the key. If there is no match, the
++     * default closure is called. The default closure is set in the map
++     * using a null key.
++     *
++     * @param objectsAndClosures a map of objects to closures
++     * @return the closure
++     * @throws IllegalArgumentException if the map is null
++     * @throws IllegalArgumentException if the map is empty
++     * @throws IllegalArgumentException if any closure in the map is null
++     * @see org.apache.commons.collections15.functors.SwitchClosure
++     */
++    public static <T> Closure<T> switchMapClosure(Map<T, Closure<T>> objectsAndClosures) {
++        Closure[] trs = null;
++        Predicate[] preds = null;
++        if (objectsAndClosures == null) {
++            throw new IllegalArgumentException("The object and closure map must not be null");
++        }
++        Closure def = (Closure) objectsAndClosures.remove(null);
++        int size = objectsAndClosures.size();
++        trs = new Closure[size];
++        preds = new Predicate[size];
++        int i = 0;
++        for (Iterator it = objectsAndClosures.entrySet().iterator(); it.hasNext();) {
++            Map.Entry entry = (Map.Entry) it.next();
++            preds[i] = EqualPredicate.getInstance(entry.getKey());
++            trs[i] = (Closure) entry.getValue();
++            i++;
++        }
++        return switchClosure(preds, trs, def);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/CollectionUtils.java
+@@ -0,0 +1,1072 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.collection.*;
++
++import java.lang.reflect.Array;
++import java.util.*;
++
++/**
++ * Provides utility methods and decorators for {@link Collection} instances.
++ *
++ * @author Rodney Waldhoff
++ * @author Paul Jack
++ * @author Stephen Colebourne
++ * @author Steve Downey
++ * @author Herve Quiroz
++ * @author Peter KoBek
++ * @author Matthew Hawthorne
++ * @author Janek Bogucki
++ * @author Phil Steitz
++ * @author Steven Melzer
++ * @author Matt Hall, John Watkinson, Jon Schewe
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 1.0
++ */
++public class CollectionUtils {
++
++    /**
++     * Constant to avoid repeated object creation
++     */
++    private static Integer INTEGER_ONE = new Integer(1);
++
++    /**
++     * An empty unmodifiable collection.
++     * The JDK provides empty Set and List implementations which could be used for
++     * this purpose. However they could be cast to Set or List which might be
++     * undesirable. This implementation only implements Collection.
++     */
++    public static final Collection EMPTY_COLLECTION = UnmodifiableCollection.decorate(new ArrayList());
++
++    /**
++     * <code>CollectionUtils</code> should not normally be instantiated.
++     */
++    public CollectionUtils() {
++    }
++
++    /**
++     * Returns a {@link Collection} containing the union
++     * of the given {@link Collection}s.
++     * <p/>
++     * The cardinality of each element in the returned {@link Collection}
++     * will be equal to the maximum of the cardinality of that element
++     * in the two given {@link Collection}s.
++     *
++     * @param a the first collection, must not be null
++     * @param b the second collection, must not be null
++     * @return the union of the two collections15
++     * @see Collection#addAll
++     */
++    public static <E> Collection<E> union(final Collection<? extends E> a, final Collection<? extends E> b) {
++        ArrayList<E> list = new ArrayList<E>();
++        Map mapa = getCardinalityMap(a);
++        Map mapb = getCardinalityMap(b);
++        Set<E> elts = new HashSet<E>(a);
++        elts.addAll(b);
++        Iterator<E> it = elts.iterator();
++        while (it.hasNext()) {
++            E obj = it.next();
++            for (int i = 0, m = Math.max(getFreq(obj, mapa), getFreq(obj, mapb)); i < m; i++) {
++                list.add(obj);
++            }
++        }
++        return list;
++    }
++
++    /**
++     * Returns a {@link Collection} containing the intersection
++     * of the given {@link Collection}s.
++     * <p/>
++     * The cardinality of each element in the returned {@link Collection}
++     * will be equal to the minimum of the cardinality of that element
++     * in the two given {@link Collection}s.
++     *
++     * @param a the first collection, must not be null
++     * @param b the second collection, must not be null
++     * @return the intersection of the two collections15
++     * @see Collection#retainAll
++     * @see #containsAny
++     */
++    public static <E> Collection<E> intersection(final Collection<? extends E> a, final Collection<? extends E> b) {
++        ArrayList<E> list = new ArrayList<E>();
++        Map mapa = getCardinalityMap(a);
++        Map mapb = getCardinalityMap(b);
++        Set<E> elts = new HashSet<E>(a);
++        elts.addAll(b);
++        Iterator<E> it = elts.iterator();
++        while (it.hasNext()) {
++            E obj = it.next();
++            for (int i = 0, m = Math.min(getFreq(obj, mapa), getFreq(obj, mapb)); i < m; i++) {
++                list.add(obj);
++            }
++        }
++        return list;
++    }
++
++    /**
++     * Returns a {@link Collection} containing the exclusive disjunction
++     * (symmetric difference) of the given {@link Collection}s.
++     * <p/>
++     * The cardinality of each element <i>e</i> in the returned {@link Collection}
++     * will be equal to
++     * <tt>max(cardinality(<i>e</i>,<i>a</i>),cardinality(<i>e</i>,<i>b</i>)) - min(cardinality(<i>e</i>,<i>a</i>),cardinality(<i>e</i>,<i>b</i>))</tt>.
++     * <p/>
++     * This is equivalent to
++     * <tt>{@link #subtract subtract}({@link #union union(a,b)},{@link #intersection intersection(a,b)})</tt>
++     * or
++     * <tt>{@link #union union}({@link #subtract subtract(a,b)},{@link #subtract subtract(b,a)})</tt>.
++     *
++     * @param a the first collection, must not be null
++     * @param b the second collection, must not be null
++     * @return the symmetric difference of the two collections15
++     */
++    public static <E> Collection<E> disjunction(final Collection<E> a, final Collection<E> b) {
++        ArrayList<E> list = new ArrayList<E>();
++        Map mapa = getCardinalityMap(a);
++        Map mapb = getCardinalityMap(b);
++        Set<E> elts = new HashSet<E>(a);
++        elts.addAll(b);
++        Iterator<E> it = elts.iterator();
++        while (it.hasNext()) {
++            E obj = it.next();
++            for (int i = 0, m = ((Math.max(getFreq(obj, mapa), getFreq(obj, mapb))) - (Math.min(getFreq(obj, mapa), getFreq(obj, mapb)))); i < m; i++) {
++                list.add(obj);
++            }
++        }
++        return list;
++    }
++
++    /**
++     * Returns a new {@link Collection} containing <tt><i>a</i> - <i>b</i></tt>.
++     * The cardinality of each element <i>e</i> in the returned {@link Collection}
++     * will be the cardinality of <i>e</i> in <i>a</i> minus the cardinality
++     * of <i>e</i> in <i>b</i>, or zero, whichever is greater.
++     *
++     * @param a the collection to subtract from, must not be null
++     * @param b the {@link Iterable} to subtract, must not be null
++     * @return a new collection with the results
++     * @see Collection#removeAll
++     */
++    public static <E> Collection<E> subtract(final Collection<? extends E> a, final Iterable<? extends E> b) {
++        ArrayList<E> list = new ArrayList<E>(a);
++        for (E e : b) {
++            list.remove(e);
++        }
++        return list;
++    }
++
++    /**
++     * Returns <code>true</code> iff at least one element is in both collections15.
++     * <p/>
++     * In other words, this method returns <code>true</code> iff the
++     * {@link #intersection} of <i>coll1</i> and <i>coll2</i> is not empty.
++     *
++     * @param coll1 the first collection, must not be null
++     * @param coll2 the first collection, must not be null
++     * @return <code>true</code> iff the intersection of the collections15 is non-empty
++     * @see #intersection
++     * @since 2.1
++     */
++    public static <E> boolean containsAny(final Collection<? extends E> coll1, final Collection<? extends E> coll2) {
++        if (coll1.size() < coll2.size()) {
++            for (Iterator it = coll1.iterator(); it.hasNext();) {
++                if (coll2.contains(it.next())) {
++                    return true;
++                }
++            }
++        } else {
++            for (Iterator it = coll2.iterator(); it.hasNext();) {
++                if (coll1.contains(it.next())) {
++                    return true;
++                }
++            }
++        }
++        return false;
++    }
++
++    public static void main(String[] args) {
++        List<String> l1 = new ArrayList<String>();
++        l1.add("Test");
++        List<Integer> l2 = new ArrayList<Integer>();
++        l2.add(1);
++        containsAny(l1, l2);
++    }
++
++    /**
++     * Returns a {@link Map} mapping each unique element in the given
++     * {@link Iterable} to an {@link Integer} representing the number
++     * of occurrences of that element in the {@link Iterable}.
++     * <p/>
++     * Only those elements present in the Iterable will appear as
++     * keys in the map.
++     *
++     * @param iterable the collection to get the cardinality map for, must not be null
++     * @return the populated cardinality map
++     */
++    public static <E> Map<E, java.lang.Integer> getCardinalityMap(final Iterable<E> iterable) {
++        Map<E, Integer> count = new HashMap<E, Integer>();
++        for (Iterator<E> it = iterable.iterator(); it.hasNext();) {
++            E obj = it.next();
++            Integer c = count.get(obj);
++            if (c == null) {
++                count.put(obj, INTEGER_ONE);
++            } else {
++                count.put(obj, new Integer(c.intValue() + 1));
++            }
++        }
++        return count;
++    }
++
++    /**
++     * Returns <tt>true</tt> iff <i>a</i> is a sub-collection of <i>b</i>,
++     * that is, iff the cardinality of <i>e</i> in <i>a</i> is less
++     * than or equal to the cardinality of <i>e</i> in <i>b</i>,
++     * for each element <i>e</i> in <i>a</i>.
++     *
++     * @param a the first (sub?) collection, must not be null
++     * @param b the second (super?) collection, must not be null
++     * @return <code>true</code> iff <i>a</i> is a sub-collection of <i>b</i>
++     * @see #isProperSubCollection
++     * @see Collection#containsAll
++     */
++    public static <E> boolean isSubCollection(final Iterable<? extends E> a, final Iterable<? extends E> b) {
++        Map mapa = getCardinalityMap(a);
++        Map mapb = getCardinalityMap(b);
++        for (E obj : a) {
++            if (getFreq(obj, mapa) > getFreq(obj, mapb)) {
++                return false;
++            }
++        }
++        return true;
++    }
++
++    /**
++     * Returns <tt>true</tt> iff <i>a</i> is a <i>proper</i> sub-collection of <i>b</i>,
++     * that is, iff the cardinality of <i>e</i> in <i>a</i> is less
++     * than or equal to the cardinality of <i>e</i> in <i>b</i>,
++     * for each element <i>e</i> in <i>a</i>, and there is at least one
++     * element <i>f</i> such that the cardinality of <i>f</i> in <i>b</i>
++     * is strictly greater than the cardinality of <i>f</i> in <i>a</i>.
++     * <p/>
++     * The implementation assumes
++     * <ul>
++     * <li><code>a.size()</code> and <code>b.size()</code> represent the
++     * total cardinality of <i>a</i> and <i>b</i>, resp. </li>
++     * <li><code>a.size() < Integer.MAXVALUE</code></li>
++     * </ul>
++     *
++     * @param a the first (sub?) collection, must not be null
++     * @param b the second (super?) collection, must not be null
++     * @return <code>true</code> iff <i>a</i> is a <i>proper</i> sub-collection of <i>b</i>
++     * @see #isSubCollection
++     * @see Collection#containsAll
++     */
++    public static <E> boolean isProperSubCollection(final Collection<? extends E> a, final Collection<? extends E> b) {
++        return (a.size() < b.size()) && CollectionUtils.isSubCollection(a, b);
++    }
++
++    /**
++     * Returns <tt>true</tt> iff the given {@link Collection}s contain
++     * exactly the same elements with exactly the same cardinalities.
++     * <p/>
++     * That is, iff the cardinality of <i>e</i> in <i>a</i> is
++     * equal to the cardinality of <i>e</i> in <i>b</i>,
++     * for each element <i>e</i> in <i>a</i> or <i>b</i>.
++     *
++     * @param a the first collection, must not be null
++     * @param b the second collection, must not be null
++     * @return <code>true</code> iff the collections15 contain the same elements with the same cardinalities.
++     */
++    public static <E> boolean isEqualCollection(final Collection<? extends E> a, final Collection<? extends E> b) {
++        if (a.size() != b.size()) {
++            return false;
++        } else {
++            Map mapa = getCardinalityMap(a);
++            Map mapb = getCardinalityMap(b);
++            if (mapa.size() != mapb.size()) {
++                return false;
++            } else {
++                Iterator it = mapa.keySet().iterator();
++                while (it.hasNext()) {
++                    Object obj = it.next();
++                    if (getFreq(obj, mapa) != getFreq(obj, mapb)) {
++                        return false;
++                    }
++                }
++                return true;
++            }
++        }
++    }
++
++    /**
++     * Returns the number of occurrences of <i>obj</i> in <i>coll</i>.
++     *
++     * @param obj  the object to find the cardinality of
++     * @param coll the collection to search
++     * @return the the number of occurrences of obj in coll
++     */
++    public static <E> int cardinality(E obj, final Collection<? super E> coll) {
++        if (coll instanceof Set) {
++            return (coll.contains(obj) ? 1 : 0);
++        }
++        if (coll instanceof Bag) {
++            return ((Bag) coll).getCount(obj);
++        }
++        int count = 0;
++        if (obj == null) {
++            for (Iterator it = coll.iterator(); it.hasNext();) {
++                if (it.next() == null) {
++                    count++;
++                }
++            }
++        } else {
++            for (Iterator it = coll.iterator(); it.hasNext();) {
++                if (obj.equals(it.next())) {
++                    count++;
++                }
++            }
++        }
++        return count;
++    }
++
++    /**
++     * Finds the first element in the given iterable which matches the given predicate.
++     * <p/>
++     * If the input iterable or predicate is null, or no element of the iterable
++     * matches the predicate, null is returned.
++     *
++     * @param iterable the iterable to search, may be null
++     * @param predicate  the predicate to use, may be null
++     * @return the first element of the iterable which matches the predicate or null if none could be found
++     */
++    public static <E> E find(Iterable<E> iterable, Predicate<? super E> predicate) {
++        if (iterable != null && predicate != null) {
++            for (Iterator<E> iter = iterable.iterator(); iter.hasNext();) {
++                E item = iter.next();
++                if (predicate.evaluate(item)) {
++                    return item;
++                }
++            }
++        }
++        return null;
++    }
++
++    /**
++     * Executes the given closure on each element in the iterable.
++     * <p/>
++     * If the input iterable or closure is null, there is no change made.
++     *
++     * @param iterable the iterable to get the input from, may be null
++     * @param closure    the closure to perform, may be null
++     */
++    public static <E> void forAllDo(Iterable<E> iterable, Closure<? super E> closure) {
++        if (iterable != null && closure != null) {
++            for (Iterator<E> it = iterable.iterator(); it.hasNext();) {
++                closure.execute(it.next());
++            }
++        }
++    }
++
++    /**
++     * Filter the iterable by applying a Predicate to each element. If the
++     * predicate returns false, remove the element.
++     * <p/>
++     * If the input iterable or predicate is null, there is no change made.
++     *
++     * @param iterable the iterable to get the input from, may be null
++     * @param predicate  the predicate to use as a filter, may be null
++     */
++    public static <E> void filter(Iterable<E> iterable, Predicate<? super E> predicate) {
++        if (iterable != null && predicate != null) {
++            for (Iterator<E> it = iterable.iterator(); it.hasNext();) {
++                if (predicate.evaluate(it.next()) == false) {
++                    it.remove();
++                }
++            }
++        }
++    }
++
++    /**
++     * Transform the collection by applying a Transformer to each element.
++     * <p/>
++     * If the input collection or transformer is null, there is no change made.
++     * <p/>
++     * This routine is best for Lists, for which set() is used to do the
++     * transformations "in place."  For other Collections, clear() and addAll()
++     * are used to replace elements.
++     * <p/>
++     * If the input collection controls its input, such as a Set, and the
++     * Transformer creates duplicates (or are otherwise invalid), the
++     * collection may reduce in size due to calling this method.
++     *
++     * @param collection  the collection to get the input from, may be null
++     * @param transformer the transformer to perform, may be null
++     */
++    public static <E> void transform(Collection<E> collection, Transformer<? super E, ? extends E> transformer) {
++        if (collection != null && transformer != null) {
++            if (collection instanceof List) {
++                List<E> list = (List<E>) collection;
++                for (ListIterator<E> it = list.listIterator(); it.hasNext();) {
++                    it.set(transformer.transform(it.next()));
++                }
++            } else {
++                Collection<E> resultCollection = collect(collection, transformer);
++                collection.clear();
++                collection.addAll(resultCollection);
++            }
++        }
++    }
++
++    /**
++     * Counts the number of elements in the input collection that match the predicate.
++     * <p/>
++     * A <code>null</code> collection or predicate matches no elements.
++     *
++     * @param inputIterable the collection to get the input from, may be null
++     * @param predicate       the predicate to use, may be null
++     * @return the number of matches for the predicate in the collection
++     */
++    public static <E> int countMatches(Iterable<E> inputIterable, Predicate<? super E> predicate) {
++        int count = 0;
++        if (inputIterable != null && predicate != null) {
++            for (Iterator<E> it = inputIterable.iterator(); it.hasNext();) {
++                if (predicate.evaluate(it.next())) {
++                    count++;
++                }
++            }
++        }
++        return count;
++    }
++
++    /**
++     * Answers true if a predicate is true for at least one element of a iterable.
++     * <p/>
++     * A <code>null</code> iterable or predicate returns false.
++     *
++     * @param iterable the iterable to get the input from, may be null
++     * @param predicate  the predicate to use, may be null
++     * @return true if at least one element of the iterable matches the predicate
++     */
++    public static <E> boolean exists(Iterable<E> iterable, Predicate<? super E> predicate) {
++        if (iterable != null && predicate != null) {
++            for (Iterator<E> it = iterable.iterator(); it.hasNext();) {
++                if (predicate.evaluate(it.next())) {
++                    return true;
++                }
++            }
++        }
++        return false;
++    }
++
++    /**
++     * Selects all elements from input collection which match the given predicate
++     * into an output collection.
++     * <p/>
++     * A <code>null</code> predicate matches no elements.
++     *
++     * @param inputCollection the collection to get the input from, may not be null
++     * @param predicate       the predicate to use, may be null
++     * @return the elements matching the predicate (new list)
++     * @throws NullPointerException if the input collection is null
++     */
++    public static <E> Collection<E> select(Collection<E> inputCollection, Predicate<? super E> predicate) {
++        return select(inputCollection, predicate, new ArrayList<E>(inputCollection.size()));
++    }
++
++    /**
++     * Selects all elements from input collection which match the given predicate
++     * and adds them to outputCollection.
++     * <p/>
++     * If the input collection or predicate is null, there is no change to the
++     * output collection.
++     *
++     * @param inputCollection  the collection to get the input from, may be null
++     * @param predicate        the predicate to use, may be null
++     * @param outputCollection the collection to output into, may not be null
++     */
++    public static <E, C extends Collection<? super E>> C select(Iterable<E> inputCollection, Predicate<? super E> predicate, C outputCollection) {
++        if (inputCollection != null && predicate != null) {
++            for (Iterator<E> iter = inputCollection.iterator(); iter.hasNext();) {
++                E item = iter.next();
++                if (predicate.evaluate(item)) {
++                    outputCollection.add(item);
++                }
++            }
++        }
++        return outputCollection;
++    }
++
++    /**
++     * Selects all elements from inputCollection which don't match the given predicate
++     * into an output collection.
++     * <p/>
++     * If the input predicate is <code>null</code>, the result is an empty list.
++     *
++     * @param inputCollection the collection to get the input from, may not be null
++     * @param predicate       the predicate to use, may be null
++     * @return the elements <b>not</b> matching the predicate (new list)
++     * @throws NullPointerException if the input collection is null
++     */
++    public static <E> Collection<E> selectRejected(Collection<E> inputCollection, Predicate<? super E> predicate) {
++        ArrayList<E> answer = new ArrayList<E>(inputCollection.size());
++        selectRejected(inputCollection, predicate, answer);
++        return answer;
++    }
++
++    /**
++     * Selects all elements from inputIterable which don't match the given predicate
++     * and adds them to outputCollection.
++     * <p/>
++     * If the input predicate is <code>null</code>, no elements are added to <code>outputCollection</code>.
++     *
++     * @param inputIterable  the collection to get the input from, may be null
++     * @param predicate        the predicate to use, may be null
++     * @param outputCollection the collection to output into, may not be null
++     */
++    public static <E> void selectRejected(Iterable<E> inputIterable, Predicate<? super E> predicate, Collection<? super E> outputCollection) {
++        if (inputIterable != null && predicate != null) {
++            for (Iterator<E> iter = inputIterable.iterator(); iter.hasNext();) {
++                E item = iter.next();
++                if (predicate.evaluate(item) == false) {
++                    outputCollection.add(item);
++                }
++            }
++        }
++    }
++
++    /**
++     * Returns a new Collection consisting of the elements of inputCollection transformed
++     * by the given transformer.
++     * <p/>
++     * If the input transformer is null, the result is an empty list.
++     *
++     * @param inputCollection the collection to get the input from, may not be null
++     * @param transformer     the transformer to use, may be null
++     * @return the transformed result (new list)
++     * @throws NullPointerException if the input collection is null
++     */
++    public static <I,O> Collection<O> collect(Collection<I> inputCollection, Transformer<? super I, ? extends O> transformer) {
++        ArrayList<O> answer = new ArrayList<O>(inputCollection.size());
++        collect(inputCollection, transformer, answer);
++        return answer;
++    }
++
++    /**
++     * Transforms all elements from the inputIterator with the given transformer
++     * and adds them to the outputCollection.
++     * <p/>
++     * If the input iterator or transformer is null, the result is an empty list.
++     *
++     * @param inputIterator the iterator to get the input from, may be null
++     * @param transformer   the transformer to use, may be null
++     * @return the transformed result (new list)
++     */
++    public static <I,O> Collection<O> collect(Iterator<I> inputIterator, Transformer<? super I, ? extends O> transformer) {
++        ArrayList<O> answer = new ArrayList<O>();
++        collect(inputIterator, transformer, answer);
++        return answer;
++    }
++
++    /**
++     * Transforms all elements from inputCollection with the given transformer
++     * and adds them to the outputCollection.
++     * <p/>
++     * If the input collection or transformer is null, there is no change to the
++     * output collection.
++     *
++     * @param inputCollection  the collection to get the input from, may be null
++     * @param transformer      the transformer to use, may not be null
++     * @param outputCollection the collection to output into, may not be null
++     * @return the outputCollection with the transformed input added
++     * @throws NullPointerException if the output collection is null
++     */
++    public static <I,O,C extends Collection<O>> C collect(Iterable<I> inputCollection, final Transformer<? super I, ? extends O> transformer, final C outputCollection) {
++        if (inputCollection != null) {
++            return collect(inputCollection.iterator(), transformer, outputCollection);
++        }
++        return outputCollection;
++    }
++
++    /**
++     * Transforms all elements from the inputIterator with the given transformer
++     * and adds them to the outputCollection.
++     * <p/>
++     * If the input iterator or transformer is null, there is no change to the
++     * output collection.
++     *
++     * @param inputIterator    the iterator to get the input from, may be null
++     * @param transformer      the transformer to use, may not be null
++     * @param outputCollection the collection to output into, may not be null
++     * @return the outputCollection with the transformed input added
++     * @throws NullPointerException if the output collection is null
++     */
++    public static <I,O,C extends Collection<O>> C collect(Iterator<I> inputIterator, final Transformer<? super I, ? extends O> transformer, final C outputCollection) {
++        if (inputIterator != null && transformer != null) {
++            while (inputIterator.hasNext()) {
++                I item = inputIterator.next();
++                O value = transformer.transform(item);
++                outputCollection.add(value);
++            }
++        }
++        return outputCollection;
++    }
++
++    /**
++     * Adds all elements in the iteration to the given collection.
++     * @deprecated Replaced by {@link Collection#addAll(java.util.Collection<? extends E>)}
++     *
++     * @param collection the collection to add to
++     * @param iterator   the iterator of elements to add, may not be null
++     * @throws NullPointerException if the collection or iterator is null
++     */
++    public static <E> void addAll(Collection<E> collection, Iterator<? extends E> iterator) {
++        while (iterator.hasNext()) {
++            collection.add(iterator.next());
++        }
++    }
++
++    /**
++     * Adds all elements in the enumeration to the given collection.
++     * @deprecated Replaced by {@link Collection#addAll(java.util.Collection<? extends E>)}
++     *
++     * @param collection  the collection to add to
++     * @param enumeration the enumeration of elements to add, may not be null
++     * @throws NullPointerException if the collection or enumeration is null
++     */
++    public static <E> void addAll(Collection<E> collection, Enumeration<? extends E> enumeration) {
++        while (enumeration.hasMoreElements()) {
++            collection.add(enumeration.nextElement());
++        }
++    }
++
++    /**
++     * Adds all elements in the array to the given collection.
++     *
++     * @param collection the collection to add to, may not be null
++     * @param elements   the array of elements to add, may not be null
++     * @throws NullPointerException if the collection or array is null
++     */
++    public static <E, T extends E> void addAll(Collection<E> collection, T... elements) {
++        for (int i = 0, size = elements.length; i < size; i++) {
++            collection.add(elements[i]);
++        }
++    }
++
++    /**
++     * Given an Object, and an index, returns the nth value in the
++     * object.
++     * <ul>
++     * <li>If obj is a Map, returns the nth value from the <b>keySet</b> iterator, unless
++     * the Map contains an Integer key with integer value = idx, in which case the
++     * corresponding map entry value is returned.  If idx exceeds the number of entries in
++     * the map, an empty Iterator is returned.
++     * <li>If obj is a List or an array, returns the nth value, throwing IndexOutOfBoundsException,
++     * ArrayIndexOutOfBoundsException, resp. if the nth value does not exist.
++     * <li>If obj is an iterator, enumeration or Collection, returns the nth value from the iterator,
++     * returning an empty Iterator (resp. Enumeration) if the nth value does not exist.
++     * <li>Returns the original obj if it is null or not a Collection or Iterator.
++     * </ul>
++     *
++     * @param obj the object to get an index of, may be null
++     * @param idx the index to get
++     * @throws IndexOutOfBoundsException
++     * @throws ArrayIndexOutOfBoundsException
++     * @deprecated use {@link #get(Object, int)} instead. Will be removed in v4.0
++     */
++    public static Object index(Object obj, int idx) {
++        return index(obj, new Integer(idx));
++    }
++
++    /**
++     * Given an Object, and a key (index), returns the value associated with
++     * that key in the Object. The following checks are made:
++     * <ul>
++     * <li>If obj is a Map, use the index as a key to get a value. If no match continue.
++     * <li>Check key is an Integer. If not, return the object passed in.
++     * <li>If obj is a Map, get the nth value from the <b>keySet</b> iterator.
++     * If the Map has fewer than n entries, return an empty Iterator.
++     * <li>If obj is a List or an array, get the nth value, throwing IndexOutOfBoundsException,
++     * ArrayIndexOutOfBoundsException, resp. if the nth value does not exist.
++     * <li>If obj is an iterator, enumeration or Collection, get the nth value from the iterator,
++     * returning an empty Iterator (resp. Enumeration) if the nth value does not exist.
++     * <li>Return the original obj.
++     * </ul>
++     *
++     * @param obj   the object to get an index of
++     * @param index the index to get
++     * @return the object at the specified index
++     * @throws IndexOutOfBoundsException
++     * @throws ArrayIndexOutOfBoundsException
++     * @deprecated use {@link #get(Object, int)} instead. Will be removed in v4.0
++     */
++    public static Object index(Object obj, Object index) {
++        if (obj instanceof Map) {
++            Map map = (Map) obj;
++            if (map.containsKey(index)) {
++                return map.get(index);
++            }
++        }
++        int idx = -1;
++        if (index instanceof Integer) {
++            idx = ((Integer) index).intValue();
++        }
++        if (idx < 0) {
++            return obj;
++        } else if (obj instanceof Map) {
++            Map map = (Map) obj;
++            Iterator iterator = map.keySet().iterator();
++            return index(iterator, idx);
++        } else if (obj instanceof List) {
++            return ((List) obj).get(idx);
++        } else if (obj instanceof Object[]) {
++            return ((Object[]) obj)[idx];
++        } else if (obj instanceof Enumeration) {
++            Enumeration it = (Enumeration) obj;
++            while (it.hasMoreElements()) {
++                idx--;
++                if (idx == -1) {
++                    return it.nextElement();
++                } else {
++                    it.nextElement();
++                }
++            }
++        } else if (obj instanceof Iterator) {
++            return index((Iterator) obj, idx);
++        } else if (obj instanceof Collection) {
++            Iterator iterator = ((Collection) obj).iterator();
++            return index(iterator, idx);
++        }
++        return obj;
++    }
++
++    private static Object index(Iterator iterator, int idx) {
++        while (iterator.hasNext()) {
++            idx--;
++            if (idx == -1) {
++                return iterator.next();
++            } else {
++                iterator.next();
++            }
++        }
++        return iterator;
++    }
++
++    /**
++     * Returns the <code>index</code>-th value in <code>object</code>, throwing
++     * <code>IndexOutOfBoundsException</code> if there is no such element or
++     * <code>IllegalArgumentException</code> if <code>object</code> is not an
++     * instance of one of the supported types.
++     * <p/>
++     * The supported types, and associated semantics are:
++     * <ul>
++     * <li> Map -- the value returned is the <code>Map.Entry</code> in position
++     * <code>index</code> in the map's <code>entrySet</code> iterator,
++     * if there is such an entry.</li>
++     * <li> List -- this method is equivalent to the list's get method.</li>
++     * <li> Array -- the <code>index</code>-th array entry is returned,
++     * if there is such an entry; otherwise an <code>IndexOutOfBoundsException</code>
++     * is thrown.</li>
++     * <li> Collection -- the value returned is the <code>index</code>-th object
++     * returned by the collection's default iterator, if there is such an element.</li>
++     * <li> Iterator or Enumeration -- the value returned is the
++     * <code>index</code>-th object in the Iterator/Enumeration, if there
++     * is such an element.  The Iterator/Enumeration is advanced to
++     * <code>index</code> (or to the end, if <code>index</code> exceeds the
++     * number of entries) as a side effect of this method.</li>
++     * </ul>
++     *
++     * @param object the object to get a value from
++     * @param index  the index to get
++     * @return the object at the specified index
++     * @throws IndexOutOfBoundsException if the index is invalid
++     * @throws IllegalArgumentException  if the object type is invalid
++     */
++    public static Object get(Object object, int index) {
++        if (index < 0) {
++            throw new IndexOutOfBoundsException("Index cannot be negative: " + index);
++        }
++        if (object instanceof Map) {
++            Map map = (Map) object;
++            Iterator iterator = map.entrySet().iterator();
++            return get(iterator, index);
++        } else if (object instanceof List) {
++            return ((List) object).get(index);
++        } else if (object instanceof Object[]) {
++            return ((Object[]) object)[index];
++        } else if (object instanceof Iterator) {
++            Iterator it = (Iterator) object;
++            while (it.hasNext()) {
++                index--;
++                if (index == -1) {
++                    return it.next();
++                } else {
++                    it.next();
++                }
++            }
++            throw new IndexOutOfBoundsException("Entry does not exist: " + index);
++        } else if (object instanceof Collection) {
++            Iterator iterator = ((Collection) object).iterator();
++            return get(iterator, index);
++        } else if (object instanceof Enumeration) {
++            Enumeration it = (Enumeration) object;
++            while (it.hasMoreElements()) {
++                index--;
++                if (index == -1) {
++                    return it.nextElement();
++                } else {
++                    it.nextElement();
++                }
++            }
++            throw new IndexOutOfBoundsException("Entry does not exist: " + index);
++        } else if (object == null) {
++            throw new IllegalArgumentException("Unsupported object type: null");
++        } else {
++            try {
++                return Array.get(object, index);
++            } catch (IllegalArgumentException ex) {
++                throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
++            }
++        }
++    }
++
++    /**
++     * Gets the size of the collection/iterator specified.
++     * <p/>
++     * This method can handles objects as follows
++     * <ul>
++     * <li>Collection - the collection size
++     * <li>Map - the map size
++     * <li>Array - the array size
++     * <li>Iterator - the number of elements remaining in the iterator
++     * <li>Enumeration - the number of elements remaining in the enumeration
++     * </ul>
++     *
++     * @param object the object to get the size of
++     * @return the size of the specified collection
++     * @throws IllegalArgumentException thrown if object is not recognised or null
++     * @since Commons Collections 3.1
++     */
++    public static int size(Object object) {
++        int total = 0;
++        if (object instanceof Map) {
++            total = ((Map) object).size();
++        } else if (object instanceof Collection) {
++            total = ((Collection) object).size();
++        } else if (object instanceof Object[]) {
++            total = ((Object[]) object).length;
++        } else if (object instanceof Iterator) {
++            Iterator it = (Iterator) object;
++            while (it.hasNext()) {
++                total++;
++                it.next();
++            }
++        } else if (object instanceof Enumeration) {
++            Enumeration it = (Enumeration) object;
++            while (it.hasMoreElements()) {
++                total++;
++                it.nextElement();
++            }
++        } else if (object == null) {
++            throw new IllegalArgumentException("Unsupported object type: null");
++        } else {
++            try {
++                total = Array.getLength(object);
++            } catch (IllegalArgumentException ex) {
++                throw new IllegalArgumentException("Unsupported object type: " + object.getClass().getName());
++            }
++        }
++        return total;
++    }
++
++    /**
++     * Reverses the order of the given array.
++     *
++     * @param array the array to reverse
++     */
++    public static void reverseArray(Object[] array) {
++        int i = 0;
++        int j = array.length - 1;
++        Object tmp;
++
++        while (j > i) {
++            tmp = array[j];
++            array[j] = array[i];
++            array[i] = tmp;
++            j--;
++            i++;
++        }
++    }
++
++    private static final int getFreq(final Object obj, final Map freqMap) {
++        Integer count = (Integer) freqMap.get(obj);
++        if (count != null) {
++            return count.intValue();
++        }
++        return 0;
++    }
++
++    /**
++     * Returns true if no more elements can be added to the Collection.
++     * <p/>
++     * This method uses the {@link BoundedCollection} interface to determine the
++     * full status. If the collection does not implement this interface then
++     * false is returned.
++     * <p/>
++     * The collection does not have to implement this interface directly.
++     * If the collection has been decorated using the decorators subpackage
++     * then these will be removed to access the BoundedCollection.
++     *
++     * @param coll the collection to check
++     * @return true if the BoundedCollection is full
++     * @throws NullPointerException if the collection is null
++     */
++    public static boolean isFull(Collection coll) {
++        if (coll == null) {
++            throw new NullPointerException("The collection must not be null");
++        }
++        if (coll instanceof BoundedCollection) {
++            return ((BoundedCollection) coll).isFull();
++        }
++        try {
++            BoundedCollection bcoll = UnmodifiableBoundedCollection.decorateUsing(coll);
++            return bcoll.isFull();
++
++        } catch (IllegalArgumentException ex) {
++            return false;
++        }
++    }
++
++    /**
++     * Get the maximum number of elements that the Collection can contain.
++     * <p/>
++     * This method uses the {@link BoundedCollection} interface to determine the
++     * maximum size. If the collection does not implement this interface then
++     * -1 is returned.
++     * <p/>
++     * The collection does not have to implement this interface directly.
++     * If the collection has been decorated using the decorators subpackage
++     * then these will be removed to access the BoundedCollection.
++     *
++     * @param coll the collection to check
++     * @return the maximum size of the BoundedCollection, -1 if no maximum size
++     * @throws NullPointerException if the collection is null
++     */
++    public static int maxSize(Collection coll) {
++        if (coll == null) {
++            throw new NullPointerException("The collection must not be null");
++        }
++        if (coll instanceof BoundedCollection) {
++            return ((BoundedCollection) coll).maxSize();
++        }
++        try {
++            BoundedCollection bcoll = UnmodifiableBoundedCollection.decorateUsing(coll);
++            return bcoll.maxSize();
++
++        } catch (IllegalArgumentException ex) {
++            return -1;
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a synchronized collection backed by the given collection.
++     * <p/>
++     * You must manually synchronize on the returned buffer's iterator to
++     * avoid non-deterministic behavior:
++     * <p/>
++     * <pre>
++     * Collection c = CollectionUtils.synchronizedCollection(myCollection);
++     * synchronized (c) {
++     *     Iterator i = c.iterator();
++     *     while (i.hasNext()) {
++     *         process (i.next());
++     *     }
++     * }
++     * </pre>
++     * <p/>
++     * This method uses the implementation in the decorators subpackage.
++     *
++     * @param collection the collection to synchronize, must not be null
++     * @return a synchronized collection backed by the given collection
++     * @throws IllegalArgumentException if the collection is null
++     */
++    public static <E> Collection<E> synchronizedCollection(Collection<E> collection) {
++        return SynchronizedCollection.decorate(collection);
++    }
++
++    /**
++     * Returns an unmodifiable collection backed by the given collection.
++     * <p/>
++     * This method uses the implementation in the decorators subpackage.
++     *
++     * @param collection the collection to make unmodifiable, must not be null
++     * @return an unmodifiable collection backed by the given collection
++     * @throws IllegalArgumentException if the collection is null
++     */
++    public static <E> Collection<E> unmodifiableCollection(Collection<E> collection) {
++        return UnmodifiableCollection.decorate(collection);
++    }
++
++    /**
++     * Returns a predicated (validating) collection backed by the given collection.
++     * <p/>
++     * Only objects that pass the test in the given predicate can be added to the collection.
++     * Trying to add an invalid object results in an IllegalArgumentException.
++     * It is important not to use the original collection after invoking this method,
++     * as it is a backdoor for adding invalid objects.
++     *
++     * @param collection the collection to predicate, must not be null
++     * @param predicate  the predicate for the collection, must not be null
++     * @return a predicated collection backed by the given collection
++     * @throws IllegalArgumentException if the Collection is null
++     */
++    public static <E> Collection<E> predicatedCollection(Collection<E> collection, Predicate<? super E> predicate) {
++        return PredicatedCollection.decorate(collection, predicate);
++    }
++
++    /**
++     * Returns a typed collection backed by the given collection.
++     * <p/>
++     * Only objects of the specified type can be added to the collection.
++     *
++     * @param collection the collection to limit to a specific type, must not be null
++     * @param type       the type of objects which may be added to the collection
++     * @return a typed collection backed by the specified collection
++     * @deprecated Obsoleted by Java 1.5 Generics.
++     */
++    public static <E> Collection<E> typedCollection(Collection<E> collection, Class<E> type) {
++        return TypedCollection.decorate(collection, type);
++    }
++
++    /**
++     * Returns a transformed bag backed by the given collection.
++     * <p/>
++     * Each object is passed through the transformer as it is added to the
++     * Collection. It is important not to use the original collection after invoking this
++     * method, as it is a backdoor for adding untransformed objects.
++     *
++     * @param collection  the collection to predicate, must not be null
++     * @param transformer the transformer for the collection, must not be null
++     * @return a transformed collection backed by the given collection
++     * @throws IllegalArgumentException if the Collection or Transformer is null
++     */
++    public static <I,O> Collection<O> transformedCollection(Collection<I> collection, Transformer<? super I, ? extends O> transformer) {
++        return TransformedCollection.decorate(collection, transformer);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/ComparatorUtils.java
+@@ -0,0 +1,233 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.comparators.*;
++
++import java.util.Collection;
++import java.util.Comparator;
++
++/**
++ * Provides convenient static utility methods for <Code>Comparator</Code>
++ * objects.
++ * <p/>
++ * Most of the functionality in this class can also be found in the
++ * <code>comparators</code> package. This class merely provides a
++ * convenient central place if you have use for more than one class
++ * in the <code>comparators</code> subpackage.
++ *
++ * @author Paul Jack
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.1
++ */
++public class ComparatorUtils {
++
++    /**
++     * ComparatorUtils should not normally be instantiated.
++     */
++    public ComparatorUtils() {
++    }
++
++    /**
++     * Comparator for natural sort order.
++     *
++     * @see ComparableComparator#getInstance
++     */
++    public static final Comparator NATURAL_COMPARATOR = ComparableComparator.getInstance();
++
++    /**
++     * Gets a comparator that uses the natural order of the objects.
++     *
++     * @return a comparator which uses natural order
++     */
++    public static Comparator naturalComparator() {
++        return NATURAL_COMPARATOR;
++    }
++
++    /**
++     * Gets a comparator that compares using two {@link Comparator}s.
++     * <p/>
++     * The second comparator is used if the first comparator returns equal.
++     *
++     * @param comparator1 the first comparator to use, not null
++     * @param comparator2 the first comparator to use, not null
++     * @return a {@link ComparatorChain} formed from the two comparators
++     * @throws NullPointerException if either comparator is null
++     * @see ComparatorChain
++     */
++    public static <T> Comparator<T> chainedComparator(Comparator<T> comparator1, Comparator<T> comparator2) {
++        return chainedComparator(new Comparator[]{comparator1, comparator2});
++    }
++
++    /**
++     * Gets a comparator that compares using an array of {@link Comparator}s, applied
++     * in sequence until one returns not equal or the array is exhausted.
++     *
++     * @param comparators the comparators to use, not null or empty or containing nulls
++     * @return a {@link ComparatorChain} formed from the input comparators
++     * @throws NullPointerException if comparators array is null or contains a null
++     * @see ComparatorChain
++     */
++    public static <T> Comparator<T> chainedComparator(Comparator<T>[] comparators) {
++        ComparatorChain chain = new ComparatorChain();
++        for (int i = 0; i < comparators.length; i++) {
++            if (comparators[i] == null) {
++                throw new NullPointerException("Comparator cannot be null");
++            }
++            chain.addComparator(comparators[i]);
++        }
++        return chain;
++    }
++
++    /**
++     * Gets a comparator that compares using a collection of {@link Comparator}s,
++     * applied in (default iterator) sequence until one returns not equal or the
++     * collection is exhausted.
++     *
++     * @param comparators the comparators to use, not null or empty or containing nulls
++     * @return a {@link ComparatorChain} formed from the input comparators
++     * @throws NullPointerException if comparators collection is null or contains a null
++     * @throws ClassCastException   if the comparators collection contains the wrong object type
++     * @see ComparatorChain
++     */
++    public static <T> Comparator<T> chainedComparator(Collection<T> comparators) {
++        return chainedComparator((Comparator[]) comparators.toArray(new Comparator[comparators.size()]));
++    }
++
++    /**
++     * Gets a comparator that reverses the order of the given comparator.
++     *
++     * @param comparator the comparator to reverse
++     * @return a comparator that reverses the order of the input comparator
++     * @see ReverseComparator
++     */
++    public static <T> Comparator<T> reversedComparator(Comparator<T> comparator) {
++        if (comparator == null) {
++            comparator = NATURAL_COMPARATOR;
++        }
++        return new ReverseComparator(comparator);
++    }
++
++    /**
++     * Gets a Comparator that can sort Boolean objects.
++     * <p/>
++     * The parameter specifies whether true or false is sorted first.
++     * <p/>
++     * The comparator throws NullPointerException if a null value is compared.
++     *
++     * @param trueFirst when <code>true</code>, sort
++     *                  <code>true</code> {@link Boolean}s before
++     *                  <code>false</code> {@link Boolean}s.
++     * @return a comparator that sorts booleans
++     */
++    public static Comparator<Boolean> booleanComparator(boolean trueFirst) {
++        return BooleanComparator.getBooleanComparator(trueFirst);
++    }
++
++    /**
++     * Gets a Comparator that controls the comparison of <code>null</code> values.
++     * <p/>
++     * The returned comparator will consider a null value to be less than
++     * any nonnull value, and equal to any other null value.  Two nonnull
++     * values will be evaluated with the given comparator.
++     *
++     * @param comparator the comparator that wants to allow nulls
++     * @return a version of that comparator that allows nulls
++     * @see NullComparator
++     */
++    public static <T> Comparator<T> nullLowComparator(Comparator<T> comparator) {
++        if (comparator == null) {
++            comparator = NATURAL_COMPARATOR;
++        }
++        return new NullComparator(comparator, false);
++    }
++
++    /**
++     * Gets a Comparator that controls the comparison of <code>null</code> values.
++     * <p/>
++     * The returned comparator will consider a null value to be greater than
++     * any nonnull value, and equal to any other null value.  Two nonnull
++     * values will be evaluated with the given comparator.
++     *
++     * @param comparator the comparator that wants to allow nulls
++     * @return a version of that comparator that allows nulls
++     * @see NullComparator
++     */
++    public static <T> Comparator<T> nullHighComparator(Comparator<T> comparator) {
++        if (comparator == null) {
++            comparator = NATURAL_COMPARATOR;
++        }
++        return new NullComparator(comparator, true);
++    }
++
++    /**
++     * Gets a Comparator that passes transformed objects to the given comparator.
++     * <p/>
++     * Objects passed to the returned comparator will first be transformed
++     * by the given transformer before they are compared by the given
++     * comparator.
++     *
++     * @param comparator  the sort order to use
++     * @param transformer the transformer to use
++     * @return a comparator that transforms its input objects before comparing them
++     * @see TransformingComparator
++     */
++    public static <I,O> Comparator<O> transformedComparator(Comparator<I> comparator, Transformer<I, O> transformer) {
++        if (comparator == null) {
++            comparator = NATURAL_COMPARATOR;
++        }
++        return new TransformingComparator(transformer, comparator);
++    }
++
++    /**
++     * Returns the smaller of the given objects according to the given
++     * comparator, returning the second object if the comparator
++     * returns equal.
++     *
++     * @param o1         the first object to compare
++     * @param o2         the second object to compare
++     * @param comparator the sort order to use
++     * @return the smaller of the two objects
++     */
++    public static <T> T min(T o1, T o2, Comparator<T> comparator) {
++        if (comparator == null) {
++            comparator = NATURAL_COMPARATOR;
++        }
++        int c = comparator.compare(o1, o2);
++        return (c < 0) ? o1 : o2;
++    }
++
++    /**
++     * Returns the larger of the given objects according to the given
++     * comparator, returning the second object if the comparator
++     * returns equal.
++     *
++     * @param o1         the first object to compare
++     * @param o2         the second object to compare
++     * @param comparator the sort order to use
++     * @return the larger of the two objects
++     */
++    public static <T> T max(T o1, T o2, Comparator<T> comparator) {
++        if (comparator == null) {
++            comparator = NATURAL_COMPARATOR;
++        }
++        int c = comparator.compare(o1, o2);
++        return (c > 0) ? o1 : o2;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/EnumerationUtils.java
+@@ -0,0 +1,53 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.iterators.EnumerationIterator;
++
++import java.util.Enumeration;
++import java.util.List;
++
++/**
++ * Provides utility methods for {@link Enumeration} instances.
++ *
++ * @author Matt Hall, John Watkinson, <a href="mailto:ggregory at seagullsw.com">Gary Gregory</a>
++ * @version $Id: EnumerationUtils.java,v 1.1 2005/10/11 17:05:19 pents90 Exp $
++ * @since Commons Collections 3.0
++ */
++public class EnumerationUtils {
++
++    /**
++     * EnumerationUtils is not normally instantiated.
++     */
++    public EnumerationUtils() {
++        // no init.
++    }
++
++    /**
++     * Creates a list based on an enumeration.
++     * <p/>
++     * <p>As the enumeration is traversed, an ArrayList of its values is
++     * created. The new list is returned.</p>
++     *
++     * @param enumeration the enumeration to traverse, which should not be <code>null</code>.
++     * @throws NullPointerException if the enumeration parameter is <code>null</code>.
++     */
++    public static <E> List<E> toList(Enumeration<E> enumeration) {
++        return IteratorUtils.toList(new EnumerationIterator(enumeration));
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/ExtendedProperties.java
+@@ -0,0 +1,1613 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.io.*;
++import java.util.*;
++
++/**
++ * This class extends normal Java properties by adding the possibility
++ * to use the same key many times concatenating the value strings
++ * instead of overwriting them.
++ * <p/>
++ * <b>Please consider using the <code>PropertiesConfiguration</code> class in
++ * Commons-Configuration as soon as it is released.</b>
++ * <p/>
++ * The Extended Properties syntax is explained here:
++ * <p/>
++ * <ul>
++ * <li>
++ * Each property has the syntax <code>key = value</code>
++ * </li>
++ * <li>
++ * The <i>key</i> may use any character but the equal sign '='.
++ * </li>
++ * <li>
++ * <i>value</i> may be separated on different lines if a backslash
++ * is placed at the end of the line that continues below.
++ * </li>
++ * <li>
++ * If <i>value</i> is a list of strings, each token is separated
++ * by a comma ','.
++ * </li>
++ * <li>
++ * Commas in each token are escaped placing a backslash right before
++ * the comma.
++ * </li>
++ * <li>
++ * Backslashes are escaped by using two consecutive backslashes i.e. \\
++ * </li>
++ * <li>
++ * If a <i>key</i> is used more than once, the values are appended
++ * like if they were on the same line separated with commas.
++ * </li>
++ * <li>
++ * Blank lines and lines starting with character '#' are skipped.
++ * </li>
++ * <li>
++ * If a property is named "include" (or whatever is defined by
++ * setInclude() and getInclude() and the value of that property is
++ * the full path to a file on disk, that file will be included into
++ * the ConfigurationsRepository. You can also pull in files relative
++ * to the parent configuration file. So if you have something
++ * like the following:
++ * <p/>
++ * include = additional.properties
++ * <p/>
++ * Then "additional.properties" is expected to be in the same
++ * directory as the parent configuration file.
++ * <p/>
++ * Duplicate name values will be replaced, so be careful.
++ * <p/>
++ * </li>
++ * </ul>
++ * <p/>
++ * <p>Here is an example of a valid extended properties file:
++ * <p/>
++ * <p><pre>
++ *      # lines starting with # are comments
++ * <p/>
++ *      # This is the simplest property
++ *      key = value
++ * <p/>
++ *      # A long property may be separated on multiple lines
++ *      longvalue = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
++ *                  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
++ * <p/>
++ *      # This is a property with many tokens
++ *      tokens_on_a_line = first token, second token
++ * <p/>
++ *      # This sequence generates exactly the same result
++ *      tokens_on_multiple_lines = first token
++ *      tokens_on_multiple_lines = second token
++ * <p/>
++ *      # commas may be escaped in tokens
++ *      commas.escaped = Hi\, what'up?
++ * </pre>
++ * <p/>
++ * <p><b>NOTE</b>: this class has <b>not</b> been written for
++ * performance nor low memory usage.  In fact, it's way slower than it
++ * could be and generates too much memory garbage.  But since
++ * performance is not an issue during intialization (and there is not
++ * much time to improve it), I wrote it this way.  If you don't like
++ * it, go ahead and tune it up!
++ *
++ * @author <a href="mailto:stefano at apache.org">Stefano Mazzocchi</a>
++ * @author <a href="mailto:jon at latchkey.com">Jon S. Stevens</a>
++ * @author <a href="mailto:daveb at miceda-data">Dave Bryson</a>
++ * @author <a href="mailto:jvanzyl at periapt.com">Jason van Zyl</a>
++ * @author <a href="mailto:geirm at optonline.net">Geir Magnusson Jr.</a>
++ * @author <a href="mailto:leon at opticode.co.za">Leon Messerschmidt</a>
++ * @author <a href="mailto:kjohnson at transparent.com">Kent Johnson</a>
++ * @author <a href="mailto:dlr at finemaltcoding.com">Daniel Rall</a>
++ * @author <a href="mailto:ipriha at surfeu.fi">Ilkka Priha</a>
++ * @author Janek Bogucki
++ * @author Mohan Kishore
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 1.0
++ */
++public class ExtendedProperties extends Hashtable {
++
++    /**
++     * Default configurations repository.
++     */
++    private ExtendedProperties defaults;
++
++    /**
++     * The file connected to this repository (holding comments and
++     * such).
++     *
++     * @serial
++     */
++    protected String file;
++
++    /**
++     * Base path of the configuration file used to create
++     * this ExtendedProperties object.
++     */
++    protected String basePath;
++
++    /**
++     * File separator.
++     */
++    protected String fileSeparator = System.getProperty("file.separator");
++
++    /**
++     * Has this configuration been intialized.
++     */
++    protected boolean isInitialized = false;
++
++    /**
++     * This is the name of the property that can point to other
++     * properties file for including other properties files.
++     */
++    protected static String include = "include";
++
++    /**
++     * These are the keys in the order they listed
++     * in the configuration file. This is useful when
++     * you wish to perform operations with configuration
++     * information in a particular order.
++     */
++    protected ArrayList<String> keysAsListed = new ArrayList<String>();
++
++    protected final static String START_TOKEN = "${";
++    protected final static String END_TOKEN = "}";
++
++
++    /**
++     * Interpolate key names to handle ${key} stuff
++     *
++     * @param base string to interpolate
++     * @return returns the key name with the ${key} substituted
++     */
++    protected String interpolate(String base) {
++        // COPIED from [configuration] 2003-12-29
++        return (interpolateHelper(base, null));
++    }
++
++    /**
++     * Recursive handler for multiple levels of interpolation.
++     * <p/>
++     * When called the first time, priorVariables should be null.
++     *
++     * @param base           string with the ${key} variables
++     * @param priorVariables serves two purposes: to allow checking for
++     *                       loops, and creating a meaningful exception message should a loop
++     *                       occur.  It's 0'th element will be set to the value of base from
++     *                       the first call.  All subsequent interpolated variables are added
++     *                       afterward.
++     * @return the string with the interpolation taken care of
++     */
++    protected String interpolateHelper(String base, List priorVariables) {
++        // COPIED from [configuration] 2003-12-29
++        if (base == null) {
++            return null;
++        }
++
++        // on the first call initialize priorVariables
++        // and add base as the first element
++        if (priorVariables == null) {
++            priorVariables = new ArrayList();
++            priorVariables.add(base);
++        }
++
++        int begin = -1;
++        int end = -1;
++        int prec = 0 - END_TOKEN.length();
++        String variable = null;
++        StringBuffer result = new StringBuffer();
++
++        // FIXME: we should probably allow the escaping of the start token
++        while (((begin = base.indexOf(START_TOKEN, prec + END_TOKEN.length())) > -1) && ((end = base.indexOf(END_TOKEN, begin)) > -1)) {
++            result.append(base.substring(prec + END_TOKEN.length(), begin));
++            variable = base.substring(begin + START_TOKEN.length(), end);
++
++            // if we've got a loop, create a useful exception message and throw
++            if (priorVariables.contains(variable)) {
++                String initialBase = priorVariables.remove(0).toString();
++                priorVariables.add(variable);
++                StringBuffer priorVariableSb = new StringBuffer();
++
++                // create a nice trace of interpolated variables like so:
++                // var1->var2->var3
++                for (Iterator it = priorVariables.iterator(); it.hasNext();) {
++                    priorVariableSb.append(it.next());
++                    if (it.hasNext()) {
++                        priorVariableSb.append("->");
++                    }
++                }
++
++                throw new IllegalStateException("infinite loop in property interpolation of " + initialBase + ": " + priorVariableSb.toString());
++            }
++            // otherwise, add this variable to the interpolation list.
++            else {
++                priorVariables.add(variable);
++            }
++
++            //QUESTION: getProperty or getPropertyDirect
++            Object value = getProperty(variable);
++            if (value != null) {
++                result.append(interpolateHelper(value.toString(), priorVariables));
++
++                // pop the interpolated variable off the stack
++                // this maintains priorVariables correctness for
++                // properties with multiple interpolations, e.g.
++                // prop.name=${some.other.prop1}/blahblah/${some.other.prop2}
++                priorVariables.remove(priorVariables.size() - 1);
++            } else if (defaults != null && defaults.getString(variable, null) != null) {
++                result.append(defaults.getString(variable));
++            } else {
++                //variable not defined - so put it back in the value
++                result.append(START_TOKEN).append(variable).append(END_TOKEN);
++            }
++            prec = end;
++        }
++        result.append(base.substring(prec + END_TOKEN.length(), base.length()));
++
++        return result.toString();
++    }
++
++    /**
++     * Inserts a backslash before every comma and backslash.
++     */
++    private static String escape(String s) {
++        StringBuffer buf = new StringBuffer(s);
++        for (int i = 0; i < buf.length(); i++) {
++            char c = buf.charAt(i);
++            if (c == ',' || c == '\\') {
++                buf.insert(i, '\\');
++                i++;
++            }
++        }
++        return buf.toString();
++    }
++
++    /**
++     * Removes a backslash from every pair of backslashes.
++     */
++    private static String unescape(String s) {
++        StringBuffer buf = new StringBuffer(s);
++        for (int i = 0; i < buf.length() - 1; i++) {
++            char c1 = buf.charAt(i);
++            char c2 = buf.charAt(i + 1);
++            if (c1 == '\\' && c2 == '\\') {
++                buf.deleteCharAt(i);
++            }
++        }
++        return buf.toString();
++    }
++
++    /**
++     * Counts the number of successive times 'ch' appears in the
++     * 'line' before the position indicated by the 'index'.
++     */
++    private static int countPreceding(String line, int index, char ch) {
++        int i;
++        for (i = index - 1; i >= 0; i--) {
++            if (line.charAt(i) != ch) {
++                break;
++            }
++        }
++        return index - 1 - i;
++    }
++
++    /**
++     * Checks if the line ends with odd number of backslashes
++     */
++    private static boolean endsWithSlash(String line) {
++        if (!line.endsWith("\\")) {
++            return false;
++        }
++        return (countPreceding(line, line.length() - 1, '\\') % 2 == 0);
++    }
++
++    /**
++     * This class is used to read properties lines.  These lines do
++     * not terminate with new-line chars but rather when there is no
++     * backslash sign a the end of the line.  This is used to
++     * concatenate multiple lines for readability.
++     */
++    static class PropertiesReader extends LineNumberReader {
++        /**
++         * Constructor.
++         *
++         * @param reader A Reader.
++         */
++        public PropertiesReader(Reader reader) {
++            super(reader);
++        }
++
++        /**
++         * Read a property.
++         *
++         * @return a String property
++         * @throws IOException if there is difficulty reading the source.
++         */
++        public String readProperty() throws IOException {
++            StringBuffer buffer = new StringBuffer();
++
++            try {
++                while (true) {
++                    String line = readLine().trim();
++                    if ((line.length() != 0) && (line.charAt(0) != '#')) {
++                        if (endsWithSlash(line)) {
++                            line = line.substring(0, line.length() - 1);
++                            buffer.append(line);
++                        } else {
++                            buffer.append(line);
++                            break;
++                        }
++                    }
++                }
++            } catch (NullPointerException ex) {
++                return null;
++            }
++
++            return buffer.toString();
++        }
++    }
++
++    /**
++     * This class divides into tokens a property value.  Token
++     * separator is "," but commas into the property value are escaped
++     * using the backslash in front.
++     */
++    static class PropertiesTokenizer extends StringTokenizer {
++        /**
++         * The property delimiter used while parsing (a comma).
++         */
++        static final String DELIMITER = ",";
++
++        /**
++         * Constructor.
++         *
++         * @param string A String.
++         */
++        public PropertiesTokenizer(String string) {
++            super(string, DELIMITER);
++        }
++
++        /**
++         * Check whether the object has more tokens.
++         *
++         * @return True if the object has more tokens.
++         */
++        public boolean hasMoreTokens() {
++            return super.hasMoreTokens();
++        }
++
++        /**
++         * Get next token.
++         *
++         * @return A String.
++         */
++        public String nextToken() {
++            StringBuffer buffer = new StringBuffer();
++
++            while (hasMoreTokens()) {
++                String token = super.nextToken();
++                if (endsWithSlash(token)) {
++                    buffer.append(token.substring(0, token.length() - 1));
++                    buffer.append(DELIMITER);
++                } else {
++                    buffer.append(token);
++                    break;
++                }
++            }
++
++            return buffer.toString().trim();
++        }
++    }
++
++    /**
++     * Creates an empty extended properties object.
++     */
++    public ExtendedProperties() {
++        super();
++    }
++
++    /**
++     * Creates and loads the extended properties from the specified file.
++     *
++     * @param file the filename to load
++     * @throws IOException if a file error occurs
++     */
++    public ExtendedProperties(String file) throws IOException {
++        this(file, null);
++    }
++
++    /**
++     * Creates and loads the extended properties from the specified file.
++     *
++     * @param file        the filename to load
++     * @param defaultFile a second filename to load default values from
++     * @throws IOException if a file error occurs
++     */
++    public ExtendedProperties(String file, String defaultFile) throws IOException {
++        this.file = file;
++
++        basePath = new File(file).getAbsolutePath();
++        basePath = basePath.substring(0, basePath.lastIndexOf(fileSeparator) + 1);
++
++        FileInputStream in = null;
++        try {
++            in = new FileInputStream(file);
++            this.load(in);
++        } finally {
++            try {
++                if (in != null) {
++                    in.close();
++                }
++            } catch (IOException ex) {
++            }
++        }
++
++        if (defaultFile != null) {
++            defaults = new ExtendedProperties(defaultFile);
++        }
++    }
++
++    /**
++     * Indicate to client code whether property
++     * resources have been initialized or not.
++     */
++    public boolean isInitialized() {
++        return isInitialized;
++    }
++
++    /**
++     * Gets the property value for including other properties files.
++     * By default it is "include".
++     *
++     * @return A String.
++     */
++    public String getInclude() {
++        return include;
++    }
++
++    /**
++     * Sets the property value for including other properties files.
++     * By default it is "include".
++     *
++     * @param inc A String.
++     */
++    public void setInclude(String inc) {
++        include = inc;
++    }
++
++    /**
++     * Load the properties from the given input stream.
++     *
++     * @param input the InputStream to load from
++     * @throws IOException if an IO error occurs
++     */
++    public void load(InputStream input) throws IOException {
++        load(input, null);
++    }
++
++    /**
++     * Load the properties from the given input stream
++     * and using the specified encoding.
++     *
++     * @param input the InputStream to load from
++     * @param enc   the encoding to use
++     * @throws IOException if an IO error occurs
++     */
++    public synchronized void load(InputStream input, String enc) throws IOException {
++        PropertiesReader reader = null;
++        if (enc != null) {
++            try {
++                reader = new PropertiesReader(new InputStreamReader(input, enc));
++
++            } catch (UnsupportedEncodingException ex) {
++                // Another try coming up....
++            }
++        }
++
++        if (reader == null) {
++            try {
++                reader = new PropertiesReader(new InputStreamReader(input, "8859_1"));
++
++            } catch (UnsupportedEncodingException ex) {
++                // ISO8859-1 support is required on java platforms but....
++                // If it's not supported, use the system default encoding
++                reader = new PropertiesReader(new InputStreamReader(input));
++            }
++        }
++
++        try {
++            while (true) {
++                String line = reader.readProperty();
++                int equalSign = line.indexOf('=');
++
++                if (equalSign > 0) {
++                    String key = line.substring(0, equalSign).trim();
++                    String value = line.substring(equalSign + 1).trim();
++
++                    // Configure produces lines like this ... just ignore them
++                    if ("".equals(value)) {
++                        continue;
++                    }
++
++                    if (getInclude() != null && key.equalsIgnoreCase(getInclude())) {
++                        // Recursively load properties files.
++                        File file = null;
++
++                        if (value.startsWith(fileSeparator)) {
++                            // We have an absolute path so we'll use this
++                            file = new File(value);
++
++                        } else {
++                            // We have a relative path, and we have two 
++                            // possible forms here. If we have the "./" form
++                            // then just strip that off first before continuing.
++                            if (value.startsWith("." + fileSeparator)) {
++                                value = value.substring(2);
++                            }
++
++                            file = new File(basePath + value);
++                        }
++
++                        if (file != null && file.exists() && file.canRead()) {
++                            load(new FileInputStream(file));
++                        }
++                    } else {
++                        addProperty(key, value);
++                    }
++                }
++            }
++        } catch (NullPointerException ex) {
++            // Should happen only when EOF is reached.
++            return;
++        } finally {
++            // Loading is initializing
++            isInitialized = true;
++        }
++    }
++
++    /**
++     * Gets a property from the configuration.
++     *
++     * @param key property to retrieve
++     * @return value as object. Will return user value if exists,
++     *         if not then default value if exists, otherwise null
++     */
++    public Object getProperty(String key) {
++        // first, try to get from the 'user value' store
++        Object obj = this.get(key);
++
++        if (obj == null) {
++            // if there isn't a value there, get it from the
++            // defaults if we have them
++            if (defaults != null) {
++                obj = defaults.get(key);
++            }
++        }
++
++        return obj;
++    }
++
++    /**
++     * Add a property to the configuration. If it already
++     * exists then the value stated here will be added
++     * to the configuration entry. For example, if
++     * <p/>
++     * <code>resource.loader = file</code>
++     * <p/>
++     * is already present in the configuration and you
++     * <p/>
++     * <code>addProperty("resource.loader", "classpath")</code>
++     * <p/>
++     * Then you will end up with a Vector like the
++     * following:
++     * <p/>
++     * <code>["file", "classpath"]</code>
++     *
++     * @param key   the key to add
++     * @param value the value to add
++     */
++    public void addProperty(String key, Object value) {
++        if (value instanceof String) {
++            String str = (String) value;
++            if (str.indexOf(PropertiesTokenizer.DELIMITER) > 0) {
++                // token contains commas, so must be split apart then added
++                PropertiesTokenizer tokenizer = new PropertiesTokenizer(str);
++                while (tokenizer.hasMoreTokens()) {
++                    String token = tokenizer.nextToken();
++                    addPropertyInternal(key, unescape(token));
++                }
++            } else {
++                // token contains no commas, so can be simply added
++                addPropertyInternal(key, unescape(str));
++            }
++        } else {
++            addPropertyInternal(key, value);
++        }
++
++        // Adding a property connotes initialization
++        isInitialized = true;
++    }
++
++    /**
++     * Adds a key/value pair to the map.  This routine does
++     * no magic morphing.  It ensures the keylist is maintained
++     *
++     * @param key   the key to store at
++     * @param value the decoded object to store
++     */
++    private void addPropertyDirect(String key, Object value) {
++        // safety check
++        if (!containsKey(key)) {
++            keysAsListed.add(key);
++        }
++        put(key, value);
++    }
++
++    /**
++     * Adds a decoded property to the map w/o checking for commas - used
++     * internally when a property has been broken up into
++     * strings that could contain escaped commas to prevent
++     * the inadvertent vectorization.
++     * <p/>
++     * Thanks to Leon Messerschmidt for this one.
++     *
++     * @param key   the key to store at
++     * @param value the decoded object to store
++     */
++    private void addPropertyInternal(String key, Object value) {
++        Object current = this.get(key);
++
++        if (current instanceof String) {
++            // one object already in map - convert it to a vector
++            Vector v = new Vector(2);
++            v.addElement(current);
++            v.addElement(value);
++            put(key, v);
++
++        } else if (current instanceof Vector) {
++            // already a vector - just add the new token
++            ((Vector) current).addElement(value);
++
++        } else {
++            // brand new key - store in keysAsListed to retain order
++            if (!containsKey(key)) {
++                keysAsListed.add(key);
++            }
++            put(key, value);
++        }
++    }
++
++    /**
++     * Set a property, this will replace any previously
++     * set values. Set values is implicitly a call
++     * to clearProperty(key), addProperty(key,value).
++     *
++     * @param key   the key to set
++     * @param value the value to set
++     */
++    public void setProperty(String key, Object value) {
++        clearProperty(key);
++        addProperty(key, value);
++    }
++
++    /**
++     * Save the properties to the given output stream.
++     * <p/>
++     * The stream is not closed, but it is flushed.
++     *
++     * @param output an OutputStream, may be null
++     * @param header a textual comment to act as a file header
++     * @throws IOException if an IO error occurs
++     */
++    public synchronized void save(OutputStream output, String header) throws IOException {
++        if (output == null) {
++            return;
++        }
++        PrintWriter theWrtr = new PrintWriter(output);
++        if (header != null) {
++            theWrtr.println(header);
++        }
++
++        Enumeration theKeys = keys();
++        while (theKeys.hasMoreElements()) {
++            String key = (String) theKeys.nextElement();
++            Object value = get(key);
++            if (value != null) {
++                if (value instanceof String) {
++                    StringBuffer currentOutput = new StringBuffer();
++                    currentOutput.append(key);
++                    currentOutput.append("=");
++                    currentOutput.append(escape((String) value));
++                    theWrtr.println(currentOutput.toString());
++
++                } else if (value instanceof Vector) {
++                    Vector values = (Vector) value;
++                    Enumeration valuesEnum = values.elements();
++                    while (valuesEnum.hasMoreElements()) {
++                        String currentElement = (String) valuesEnum.nextElement();
++                        StringBuffer currentOutput = new StringBuffer();
++                        currentOutput.append(key);
++                        currentOutput.append("=");
++                        currentOutput.append(escape(currentElement));
++                        theWrtr.println(currentOutput.toString());
++                    }
++                }
++            }
++            theWrtr.println();
++            theWrtr.flush();
++        }
++    }
++
++    /**
++     * Combines an existing Hashtable with this Hashtable.
++     * <p/>
++     * Warning: It will overwrite previous entries without warning.
++     *
++     * @param props the properties to combine
++     */
++    public void combine(ExtendedProperties props) {
++        for (Iterator it = props.getKeys(); it.hasNext();) {
++            String key = (String) it.next();
++            setProperty(key, props.get(key));
++        }
++    }
++
++    /**
++     * Clear a property in the configuration.
++     *
++     * @param key the property key to remove along with corresponding value
++     */
++    public void clearProperty(String key) {
++        if (containsKey(key)) {
++            // we also need to rebuild the keysAsListed or else
++            // things get *very* confusing
++            for (int i = 0; i < keysAsListed.size(); i++) {
++                if ((keysAsListed.get(i)).equals(key)) {
++                    keysAsListed.remove(i);
++                    break;
++                }
++            }
++            remove(key);
++        }
++    }
++
++    /**
++     * Get the list of the keys contained in the configuration
++     * repository.
++     *
++     * @return an Iterator over the keys
++     */
++    public Iterator getKeys() {
++        return keysAsListed.iterator();
++    }
++
++    /**
++     * Get the list of the keys contained in the configuration
++     * repository that match the specified prefix.
++     *
++     * @param prefix the prefix to match
++     * @return an Iterator of keys that match the prefix
++     */
++    public Iterator getKeys(String prefix) {
++        Iterator keys = getKeys();
++        ArrayList matchingKeys = new ArrayList();
++
++        while (keys.hasNext()) {
++            Object key = keys.next();
++
++            if (key instanceof String && ((String) key).startsWith(prefix)) {
++                matchingKeys.add(key);
++            }
++        }
++        return matchingKeys.iterator();
++    }
++
++    /**
++     * Create an ExtendedProperties object that is a subset
++     * of this one. Take into account duplicate keys
++     * by using the setProperty() in ExtendedProperties.
++     *
++     * @param prefix the prefix to get a subset for
++     * @return a new independent ExtendedProperties
++     */
++    public ExtendedProperties subset(String prefix) {
++        ExtendedProperties c = new ExtendedProperties();
++        Iterator keys = getKeys();
++        boolean validSubset = false;
++
++        while (keys.hasNext()) {
++            Object key = keys.next();
++
++            if (key instanceof String && ((String) key).startsWith(prefix)) {
++                if (!validSubset) {
++                    validSubset = true;
++                }
++
++                /*
++                 * Check to make sure that c.subset(prefix) doesn't
++                 * blow up when there is only a single property
++                 * with the key prefix. This is not a useful
++                 * subset but it is a valid subset.
++                 */
++                String newKey = null;
++                if (((String) key).length() == prefix.length()) {
++                    newKey = prefix;
++                } else {
++                    newKey = ((String) key).substring(prefix.length() + 1);
++                }
++
++                /*
++                 *  use addPropertyDirect() - this will plug the data as 
++                 *  is into the Map, but will also do the right thing
++                 *  re key accounting
++                 */
++                c.addPropertyDirect(newKey, get(key));
++            }
++        }
++
++        if (validSubset) {
++            return c;
++        } else {
++            return null;
++        }
++    }
++
++    /**
++     * Display the configuration for debugging purposes to System.out.
++     */
++    public void display() {
++        Iterator i = getKeys();
++
++        while (i.hasNext()) {
++            String key = (String) i.next();
++            Object value = get(key);
++            System.out.println(key + " => " + value);
++        }
++    }
++
++    /**
++     * Get a string associated with the given configuration key.
++     *
++     * @param key The configuration key.
++     * @return The associated string.
++     * @throws ClassCastException is thrown if the key maps to an
++     *                            object that is not a String.
++     */
++    public String getString(String key) {
++        return getString(key, null);
++    }
++
++    /**
++     * Get a string associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated string if key is found,
++     *         default value otherwise.
++     * @throws ClassCastException is thrown if the key maps to an
++     *                            object that is not a String.
++     */
++    public String getString(String key, String defaultValue) {
++        Object value = get(key);
++
++        if (value instanceof String) {
++            return interpolate((String) value);
++
++        } else if (value == null) {
++            if (defaults != null) {
++                return interpolate(defaults.getString(key, defaultValue));
++            } else {
++                return interpolate(defaultValue);
++            }
++        } else if (value instanceof Vector) {
++            return interpolate((String) ((Vector) value).get(0));
++        } else {
++            throw new ClassCastException('\'' + key + "' doesn't map to a String object");
++        }
++    }
++
++    /**
++     * Get a list of properties associated with the given
++     * configuration key.
++     *
++     * @param key The configuration key.
++     * @return The associated properties if key is found.
++     * @throws ClassCastException       is thrown if the key maps to an
++     *                                  object that is not a String/Vector.
++     * @throws IllegalArgumentException if one of the tokens is
++     *                                  malformed (does not contain an equals sign).
++     */
++    public Properties getProperties(String key) {
++        return getProperties(key, new Properties());
++    }
++
++    /**
++     * Get a list of properties associated with the given
++     * configuration key.
++     *
++     * @param key The configuration key.
++     * @return The associated properties if key is found.
++     * @throws ClassCastException       is thrown if the key maps to an
++     *                                  object that is not a String/Vector.
++     * @throws IllegalArgumentException if one of the tokens is
++     *                                  malformed (does not contain an equals sign).
++     */
++    public Properties getProperties(String key, Properties defaults) {
++        /*
++         * Grab an array of the tokens for this key.
++         */
++        String[] tokens = getStringArray(key);
++
++        // Each token is of the form 'key=value'.
++        Properties props = new Properties(defaults);
++        for (int i = 0; i < tokens.length; i++) {
++            String token = tokens[i];
++            int equalSign = token.indexOf('=');
++            if (equalSign > 0) {
++                String pkey = token.substring(0, equalSign).trim();
++                String pvalue = token.substring(equalSign + 1).trim();
++                props.put(pkey, pvalue);
++            } else {
++                throw new IllegalArgumentException('\'' + token + "' does not contain " + "an equals sign");
++            }
++        }
++        return props;
++    }
++
++    /**
++     * Get an array of strings associated with the given configuration
++     * key.
++     *
++     * @param key The configuration key.
++     * @return The associated string array if key is found.
++     * @throws ClassCastException is thrown if the key maps to an
++     *                            object that is not a String/Vector.
++     */
++    public String[] getStringArray(String key) {
++        Object value = get(key);
++
++        // What's your vector, Victor?
++        Vector vector;
++        if (value instanceof String) {
++            vector = new Vector(1);
++            vector.addElement(value);
++
++        } else if (value instanceof Vector) {
++            vector = (Vector) value;
++
++        } else if (value == null) {
++            if (defaults != null) {
++                return defaults.getStringArray(key);
++            } else {
++                return new String[0];
++            }
++        } else {
++            throw new ClassCastException('\'' + key + "' doesn't map to a String/Vector object");
++        }
++
++        String[] tokens = new String[vector.size()];
++        for (int i = 0; i < tokens.length; i++) {
++            tokens[i] = (String) vector.elementAt(i);
++        }
++
++        return tokens;
++    }
++
++    /**
++     * Get a Vector of strings associated with the given configuration
++     * key.
++     *
++     * @param key The configuration key.
++     * @return The associated Vector.
++     * @throws ClassCastException is thrown if the key maps to an
++     *                            object that is not a Vector.
++     */
++    public Vector getVector(String key) {
++        return getVector(key, null);
++    }
++
++    /**
++     * Get a Vector of strings associated with the given configuration
++     * key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated Vector.
++     * @throws ClassCastException is thrown if the key maps to an
++     *                            object that is not a Vector.
++     */
++    public Vector getVector(String key, Vector defaultValue) {
++        Object value = get(key);
++
++        if (value instanceof Vector) {
++            return (Vector) value;
++
++        } else if (value instanceof String) {
++            Vector v = new Vector(1);
++            v.addElement(value);
++            put(key, v);
++            return v;
++
++        } else if (value == null) {
++            if (defaults != null) {
++                return defaults.getVector(key, defaultValue);
++            } else {
++                return ((defaultValue == null) ? new Vector() : defaultValue);
++            }
++        } else {
++            throw new ClassCastException('\'' + key + "' doesn't map to a Vector object");
++        }
++    }
++
++    /**
++     * Get a boolean associated with the given configuration key.
++     *
++     * @param key The configuration key.
++     * @return The associated boolean.
++     * @throws NoSuchElementException is thrown if the key doesn't
++     *                                map to an existing object.
++     * @throws ClassCastException     is thrown if the key maps to an
++     *                                object that is not a Boolean.
++     */
++    public boolean getBoolean(String key) {
++        Boolean b = getBoolean(key, null);
++        if (b != null) {
++            return b.booleanValue();
++        } else {
++            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
++        }
++    }
++
++    /**
++     * Get a boolean associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated boolean.
++     * @throws ClassCastException is thrown if the key maps to an
++     *                            object that is not a Boolean.
++     */
++    public boolean getBoolean(String key, boolean defaultValue) {
++        return getBoolean(key, new Boolean(defaultValue)).booleanValue();
++    }
++
++    /**
++     * Get a boolean associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated boolean if key is found and has valid
++     *         format, default value otherwise.
++     * @throws ClassCastException is thrown if the key maps to an
++     *                            object that is not a Boolean.
++     */
++    public Boolean getBoolean(String key, Boolean defaultValue) {
++
++        Object value = get(key);
++
++        if (value instanceof Boolean) {
++            return (Boolean) value;
++
++        } else if (value instanceof String) {
++            String s = testBoolean((String) value);
++            Boolean b = new Boolean(s);
++            put(key, b);
++            return b;
++
++        } else if (value == null) {
++            if (defaults != null) {
++                return defaults.getBoolean(key, defaultValue);
++            } else {
++                return defaultValue;
++            }
++        } else {
++            throw new ClassCastException('\'' + key + "' doesn't map to a Boolean object");
++        }
++    }
++
++    /**
++     * Test whether the string represent by value maps to a boolean
++     * value or not. We will allow <code>true</code>, <code>on</code>,
++     * and <code>yes</code> for a <code>true</code> boolean value, and
++     * <code>false</code>, <code>off</code>, and <code>no</code> for
++     * <code>false</code> boolean values.  Case of value to test for
++     * boolean status is ignored.
++     *
++     * @param value the value to test for boolean state
++     * @return <code>true</code> or <code>false</code> if the supplied
++     *         text maps to a boolean value, or <code>null</code> otherwise.
++     */
++    public String testBoolean(String value) {
++        String s = value.toLowerCase();
++
++        if (s.equals("true") || s.equals("on") || s.equals("yes")) {
++            return "true";
++        } else if (s.equals("false") || s.equals("off") || s.equals("no")) {
++            return "false";
++        } else {
++            return null;
++        }
++    }
++
++    /**
++     * Get a byte associated with the given configuration key.
++     *
++     * @param key The configuration key.
++     * @return The associated byte.
++     * @throws NoSuchElementException is thrown if the key doesn't
++     *                                map to an existing object.
++     * @throws ClassCastException     is thrown if the key maps to an
++     *                                object that is not a Byte.
++     * @throws NumberFormatException  is thrown if the value mapped
++     *                                by the key has not a valid number format.
++     */
++    public byte getByte(String key) {
++        Byte b = getByte(key, null);
++        if (b != null) {
++            return b.byteValue();
++        } else {
++            throw new NoSuchElementException('\'' + key + " doesn't map to an existing object");
++        }
++    }
++
++    /**
++     * Get a byte associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated byte.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Byte.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public byte getByte(String key, byte defaultValue) {
++        return getByte(key, new Byte(defaultValue)).byteValue();
++    }
++
++    /**
++     * Get a byte associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated byte if key is found and has valid
++     *         format, default value otherwise.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Byte.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public Byte getByte(String key, Byte defaultValue) {
++        Object value = get(key);
++
++        if (value instanceof Byte) {
++            return (Byte) value;
++
++        } else if (value instanceof String) {
++            Byte b = new Byte((String) value);
++            put(key, b);
++            return b;
++
++        } else if (value == null) {
++            if (defaults != null) {
++                return defaults.getByte(key, defaultValue);
++            } else {
++                return defaultValue;
++            }
++        } else {
++            throw new ClassCastException('\'' + key + "' doesn't map to a Byte object");
++        }
++    }
++
++    /**
++     * Get a short associated with the given configuration key.
++     *
++     * @param key The configuration key.
++     * @return The associated short.
++     * @throws NoSuchElementException is thrown if the key doesn't
++     *                                map to an existing object.
++     * @throws ClassCastException     is thrown if the key maps to an
++     *                                object that is not a Short.
++     * @throws NumberFormatException  is thrown if the value mapped
++     *                                by the key has not a valid number format.
++     */
++    public short getShort(String key) {
++        Short s = getShort(key, null);
++        if (s != null) {
++            return s.shortValue();
++        } else {
++            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
++        }
++    }
++
++    /**
++     * Get a short associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated short.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Short.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public short getShort(String key, short defaultValue) {
++        return getShort(key, new Short(defaultValue)).shortValue();
++    }
++
++    /**
++     * Get a short associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated short if key is found and has valid
++     *         format, default value otherwise.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Short.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public Short getShort(String key, Short defaultValue) {
++        Object value = get(key);
++
++        if (value instanceof Short) {
++            return (Short) value;
++
++        } else if (value instanceof String) {
++            Short s = new Short((String) value);
++            put(key, s);
++            return s;
++
++        } else if (value == null) {
++            if (defaults != null) {
++                return defaults.getShort(key, defaultValue);
++            } else {
++                return defaultValue;
++            }
++        } else {
++            throw new ClassCastException('\'' + key + "' doesn't map to a Short object");
++        }
++    }
++
++    /**
++     * The purpose of this method is to get the configuration resource
++     * with the given name as an integer.
++     *
++     * @param name The resource name.
++     * @return The value of the resource as an integer.
++     */
++    public int getInt(String name) {
++        return getInteger(name);
++    }
++
++    /**
++     * The purpose of this method is to get the configuration resource
++     * with the given name as an integer, or a default value.
++     *
++     * @param name The resource name
++     * @param def  The default value of the resource.
++     * @return The value of the resource as an integer.
++     */
++    public int getInt(String name, int def) {
++        return getInteger(name, def);
++    }
++
++    /**
++     * Get a int associated with the given configuration key.
++     *
++     * @param key The configuration key.
++     * @return The associated int.
++     * @throws NoSuchElementException is thrown if the key doesn't
++     *                                map to an existing object.
++     * @throws ClassCastException     is thrown if the key maps to an
++     *                                object that is not a Integer.
++     * @throws NumberFormatException  is thrown if the value mapped
++     *                                by the key has not a valid number format.
++     */
++    public int getInteger(String key) {
++        Integer i = getInteger(key, null);
++        if (i != null) {
++            return i.intValue();
++        } else {
++            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
++        }
++    }
++
++    /**
++     * Get a int associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated int.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Integer.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public int getInteger(String key, int defaultValue) {
++        Integer i = getInteger(key, null);
++
++        if (i == null) {
++            return defaultValue;
++        }
++        return i.intValue();
++    }
++
++    /**
++     * Get a int associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated int if key is found and has valid
++     *         format, default value otherwise.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Integer.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public Integer getInteger(String key, Integer defaultValue) {
++        Object value = get(key);
++
++        if (value instanceof Integer) {
++            return (Integer) value;
++
++        } else if (value instanceof String) {
++            Integer i = new Integer((String) value);
++            put(key, i);
++            return i;
++
++        } else if (value == null) {
++            if (defaults != null) {
++                return defaults.getInteger(key, defaultValue);
++            } else {
++                return defaultValue;
++            }
++        } else {
++            throw new ClassCastException('\'' + key + "' doesn't map to a Integer object");
++        }
++    }
++
++    /**
++     * Get a long associated with the given configuration key.
++     *
++     * @param key The configuration key.
++     * @return The associated long.
++     * @throws NoSuchElementException is thrown if the key doesn't
++     *                                map to an existing object.
++     * @throws ClassCastException     is thrown if the key maps to an
++     *                                object that is not a Long.
++     * @throws NumberFormatException  is thrown if the value mapped
++     *                                by the key has not a valid number format.
++     */
++    public long getLong(String key) {
++        Long l = getLong(key, null);
++        if (l != null) {
++            return l.longValue();
++        } else {
++            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
++        }
++    }
++
++    /**
++     * Get a long associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated long.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Long.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public long getLong(String key, long defaultValue) {
++        return getLong(key, new Long(defaultValue)).longValue();
++    }
++
++    /**
++     * Get a long associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated long if key is found and has valid
++     *         format, default value otherwise.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Long.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public Long getLong(String key, Long defaultValue) {
++        Object value = get(key);
++
++        if (value instanceof Long) {
++            return (Long) value;
++
++        } else if (value instanceof String) {
++            Long l = new Long((String) value);
++            put(key, l);
++            return l;
++
++        } else if (value == null) {
++            if (defaults != null) {
++                return defaults.getLong(key, defaultValue);
++            } else {
++                return defaultValue;
++            }
++        } else {
++            throw new ClassCastException('\'' + key + "' doesn't map to a Long object");
++        }
++    }
++
++    /**
++     * Get a float associated with the given configuration key.
++     *
++     * @param key The configuration key.
++     * @return The associated float.
++     * @throws NoSuchElementException is thrown if the key doesn't
++     *                                map to an existing object.
++     * @throws ClassCastException     is thrown if the key maps to an
++     *                                object that is not a Float.
++     * @throws NumberFormatException  is thrown if the value mapped
++     *                                by the key has not a valid number format.
++     */
++    public float getFloat(String key) {
++        Float f = getFloat(key, null);
++        if (f != null) {
++            return f.floatValue();
++        } else {
++            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
++        }
++    }
++
++    /**
++     * Get a float associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated float.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Float.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public float getFloat(String key, float defaultValue) {
++        return getFloat(key, new Float(defaultValue)).floatValue();
++    }
++
++    /**
++     * Get a float associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated float if key is found and has valid
++     *         format, default value otherwise.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Float.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public Float getFloat(String key, Float defaultValue) {
++        Object value = get(key);
++
++        if (value instanceof Float) {
++            return (Float) value;
++
++        } else if (value instanceof String) {
++            Float f = new Float((String) value);
++            put(key, f);
++            return f;
++
++        } else if (value == null) {
++            if (defaults != null) {
++                return defaults.getFloat(key, defaultValue);
++            } else {
++                return defaultValue;
++            }
++        } else {
++            throw new ClassCastException('\'' + key + "' doesn't map to a Float object");
++        }
++    }
++
++    /**
++     * Get a double associated with the given configuration key.
++     *
++     * @param key The configuration key.
++     * @return The associated double.
++     * @throws NoSuchElementException is thrown if the key doesn't
++     *                                map to an existing object.
++     * @throws ClassCastException     is thrown if the key maps to an
++     *                                object that is not a Double.
++     * @throws NumberFormatException  is thrown if the value mapped
++     *                                by the key has not a valid number format.
++     */
++    public double getDouble(String key) {
++        Double d = getDouble(key, null);
++        if (d != null) {
++            return d.doubleValue();
++        } else {
++            throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object");
++        }
++    }
++
++    /**
++     * Get a double associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated double.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Double.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public double getDouble(String key, double defaultValue) {
++        return getDouble(key, new Double(defaultValue)).doubleValue();
++    }
++
++    /**
++     * Get a double associated with the given configuration key.
++     *
++     * @param key          The configuration key.
++     * @param defaultValue The default value.
++     * @return The associated double if key is found and has valid
++     *         format, default value otherwise.
++     * @throws ClassCastException    is thrown if the key maps to an
++     *                               object that is not a Double.
++     * @throws NumberFormatException is thrown if the value mapped
++     *                               by the key has not a valid number format.
++     */
++    public Double getDouble(String key, Double defaultValue) {
++        Object value = get(key);
++
++        if (value instanceof Double) {
++            return (Double) value;
++
++        } else if (value instanceof String) {
++            Double d = new Double((String) value);
++            put(key, d);
++            return d;
++
++        } else if (value == null) {
++            if (defaults != null) {
++                return defaults.getDouble(key, defaultValue);
++            } else {
++                return defaultValue;
++            }
++        } else {
++            throw new ClassCastException('\'' + key + "' doesn't map to a Double object");
++        }
++    }
++
++    /**
++     * Convert a standard properties class into a configuration class.
++     *
++     * @param props the properties object to convert
++     * @return new ExtendedProperties created from props
++     */
++    public static ExtendedProperties convertProperties(Properties props) {
++        ExtendedProperties c = new ExtendedProperties();
++
++        for (Enumeration e = props.keys(); e.hasMoreElements();) {
++            String s = (String) e.nextElement();
++            c.setProperty(s, props.getProperty(s));
++        }
++
++        return c;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/Factory.java
+@@ -0,0 +1,44 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++/**
++ * Defines a functor interface implemented by classes that create objects.
++ * <p/>
++ * A <code>Factory</code> creates an object without using an input parameter.
++ * If an input parameter is required, then {@link Transformer} is more appropriate.
++ * <p/>
++ * Standard implementations of common factories are provided by
++ * {@link FactoryUtils}. These include factories that return a constant,
++ * a copy of a prototype or a new instance.
++ *
++ * @author Arron Bates
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.1
++ */
++public interface Factory <T> {
++
++    /**
++     * Create a new object.
++     *
++     * @return a new object
++     * @throws FunctorException (runtime) if the factory cannot create an object
++     */
++    public T create();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/FactoryUtils.java
+@@ -0,0 +1,135 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.functors.ConstantFactory;
++import org.apache.commons.collections15.functors.ExceptionFactory;
++import org.apache.commons.collections15.functors.InstantiateFactory;
++import org.apache.commons.collections15.functors.PrototypeFactory;
++
++/**
++ * <code>FactoryUtils</code> provides reference implementations and utilities
++ * for the Factory functor interface. The supplied factories are:
++ * <ul>
++ * <li>Prototype - clones a specified object
++ * <li>Reflection - creates objects using reflection
++ * <li>Constant - always returns the same object
++ * <li>Null - always returns null
++ * <li>Exception - always throws an exception
++ * </ul>
++ * All the supplied factories are Serializable.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class FactoryUtils {
++
++    /**
++     * This class is not normally instantiated.
++     */
++    public FactoryUtils() {
++        super();
++    }
++
++    /**
++     * Gets a Factory that always throws an exception.
++     * This could be useful during testing as a placeholder.
++     *
++     * @return the factory
++     * @see org.apache.commons.collections15.functors.ExceptionFactory
++     */
++    public static Factory exceptionFactory() {
++        return ExceptionFactory.INSTANCE;
++    }
++
++    /**
++     * Gets a Factory that will return null each time the factory is used.
++     * This could be useful during testing as a placeholder.
++     *
++     * @return the factory
++     * @see org.apache.commons.collections15.functors.ConstantFactory
++     */
++    public static Factory nullFactory() {
++        return ConstantFactory.NULL_INSTANCE;
++    }
++
++    /**
++     * Creates a Factory that will return the same object each time the factory
++     * is used. No check is made that the object is immutable. In general, only
++     * immutable objects should use the constant factory. Mutable objects should
++     * use the prototype factory.
++     *
++     * @param constantToReturn the constant object to return each time in the factory
++     * @return the <code>constant</code> factory.
++     * @see org.apache.commons.collections15.functors.ConstantFactory
++     */
++    public static <T> Factory<T> constantFactory(T constantToReturn) {
++        return ConstantFactory.getInstance(constantToReturn);
++    }
++
++    /**
++     * Creates a Factory that will return a clone of the same prototype object
++     * each time the factory is used. The prototype will be cloned using one of these
++     * techniques (in order):
++     * <ul>
++     * <li>public clone method
++     * <li>public copy constructor
++     * <li>serialization clone
++     * <ul>
++     *
++     * @param prototype the object to clone each time in the factory
++     * @return the <code>prototype</code> factory
++     * @throws IllegalArgumentException if the prototype is null
++     * @throws IllegalArgumentException if the prototype cannot be cloned
++     * @see org.apache.commons.collections15.functors.PrototypeFactory
++     */
++    public static <T> Factory<T> prototypeFactory(T prototype) {
++        return PrototypeFactory.getInstance(prototype);
++    }
++
++    /**
++     * Creates a Factory that can create objects of a specific type using
++     * a no-args constructor.
++     *
++     * @param classToInstantiate the Class to instantiate each time in the factory
++     * @return the <code>reflection</code> factory
++     * @throws IllegalArgumentException if the classToInstantiate is null
++     * @see org.apache.commons.collections15.functors.InstantiateFactory
++     */
++    public static <T> Factory<T> instantiateFactory(Class<T> classToInstantiate) {
++        return InstantiateFactory.getInstance(classToInstantiate, null, null);
++    }
++
++    /**
++     * Creates a Factory that can create objects of a specific type using
++     * the arguments specified to this method.
++     *
++     * @param classToInstantiate the Class to instantiate each time in the factory
++     * @param paramTypes         parameter types for the constructor, can be null
++     * @param args               the arguments to pass to the constructor, can be null
++     * @return the <code>reflection</code> factory
++     * @throws IllegalArgumentException if the classToInstantiate is null
++     * @throws IllegalArgumentException if the paramTypes and args don't match
++     * @throws IllegalArgumentException if the constructor doesn't exist
++     * @see org.apache.commons.collections15.functors.InstantiateFactory
++     */
++    public static <T> Factory<T> instantiateFactory(Class<T> classToInstantiate, Class[] paramTypes, Object[] args) {
++        return InstantiateFactory.getInstance(classToInstantiate, paramTypes, args);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/FunctorException.java
+@@ -0,0 +1,143 @@
++// GenericsNote: No conversion needed.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.io.PrintStream;
++import java.io.PrintWriter;
++
++/**
++ * Runtime exception thrown from functors.
++ * If required, a root cause error can be wrapped within this one.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class FunctorException extends RuntimeException {
++
++    /**
++     * Does JDK support nested exceptions
++     */
++    private static final boolean JDK_SUPPORTS_NESTED;
++
++    static {
++        boolean flag = false;
++        try {
++            Throwable.class.getDeclaredMethod("getCause", new Class[0]);
++            flag = true;
++        } catch (NoSuchMethodException ex) {
++            flag = false;
++        }
++        JDK_SUPPORTS_NESTED = flag;
++    }
++
++    /**
++     * Root cause of the exception
++     */
++    private final Throwable rootCause;
++
++    /**
++     * Constructs a new <code>FunctorException</code> without specified
++     * detail message.
++     */
++    public FunctorException() {
++        super();
++        this.rootCause = null;
++    }
++
++    /**
++     * Constructs a new <code>FunctorException</code> with specified
++     * detail message.
++     *
++     * @param msg the error message.
++     */
++    public FunctorException(String msg) {
++        super(msg);
++        this.rootCause = null;
++    }
++
++    /**
++     * Constructs a new <code>FunctorException</code> with specified
++     * nested <code>Throwable</code> root cause.
++     *
++     * @param rootCause the exception or error that caused this exception
++     *                  to be thrown.
++     */
++    public FunctorException(Throwable rootCause) {
++        super((rootCause == null ? null : rootCause.getMessage()));
++        this.rootCause = rootCause;
++    }
++
++    /**
++     * Constructs a new <code>FunctorException</code> with specified
++     * detail message and nested <code>Throwable</code> root cause.
++     *
++     * @param msg       the error message.
++     * @param rootCause the exception or error that caused this exception
++     *                  to be thrown.
++     */
++    public FunctorException(String msg, Throwable rootCause) {
++        super(msg);
++        this.rootCause = rootCause;
++    }
++
++    /**
++     * Gets the cause of this throwable.
++     *
++     * @return the cause of this throwable, or <code>null</code>
++     */
++    public Throwable getCause() {
++        return rootCause;
++    }
++
++    /**
++     * Prints the stack trace of this exception to the standard error stream.
++     */
++    public void printStackTrace() {
++        printStackTrace(System.err);
++    }
++
++    /**
++     * Prints the stack trace of this exception to the specified stream.
++     *
++     * @param out the <code>PrintStream</code> to use for output
++     */
++    public void printStackTrace(PrintStream out) {
++        synchronized (out) {
++            PrintWriter pw = new PrintWriter(out, false);
++            printStackTrace(pw);
++            // Flush the PrintWriter before it's GC'ed.
++            pw.flush();
++        }
++    }
++
++    /**
++     * Prints the stack trace of this exception to the specified writer.
++     *
++     * @param out the <code>PrintWriter</code> to use for output
++     */
++    public void printStackTrace(PrintWriter out) {
++        synchronized (out) {
++            super.printStackTrace(out);
++            if (rootCause != null && JDK_SUPPORTS_NESTED == false) {
++                out.print("Caused by: ");
++                rootCause.printStackTrace(out);
++            }
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/IterableMap.java
+@@ -0,0 +1,61 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.Map;
++
++/**
++ * Defines a map that can be iterated directly without needing to create an entry set.
++ * <p/>
++ * A map iterator is an efficient way of iterating over maps.
++ * There is no need to access the entry set or cast to Map Entry objects.
++ * <pre>
++ * IterableMap map = new HashedMap();
++ * MapIterator it = map.mapIterator();
++ * while (it.hasNext()) {
++ *   Object key = it.next();
++ *   Object value = it.getValue();
++ *   it.setValue("newValue");
++ * }
++ * </pre>
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface IterableMap <K,V> extends Map<K, V> {
++
++    /**
++     * Obtains a <code>MapIterator</code> over the map.
++     * <p/>
++     * A map iterator is an efficient way of iterating over maps.
++     * There is no need to access the entry set or cast to Map Entry objects.
++     * <pre>
++     * IterableMap map = new HashedMap();
++     * MapIterator it = map.mapIterator();
++     * while (it.hasNext()) {
++     *   Object key = it.next();
++     *   Object value = it.getValue();
++     *   it.setValue("newValue");
++     * }
++     * </pre>
++     *
++     * @return a map iterator
++     */
++    MapIterator<K, V> mapIterator();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/IteratorUtils.java
+@@ -0,0 +1,863 @@
++// GenericsNote: Converted, although getIterator(Object) is unsatisfying.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.iterators.*;
++
++import java.lang.reflect.Array;
++import java.lang.reflect.Method;
++import java.util.*;
++
++/**
++ * Provides static utility methods and decorators for {@link Iterator}
++ * instances. The implementations are provided in the iterators subpackage.
++ * <p/>
++ * WARNING: Due to human error certain binary incompatabilities were introduced
++ * between Commons Collections 2.1 and 3.0. The class remained source and test
++ * compatible, so if you can recompile all your classes and dependencies
++ * everything is OK. Those methods which are binary incompatible are marked as
++ * such, together with alternate solutions that are binary compatible
++ * against versions 2.1.1 and 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Phil Steitz
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.1
++ */
++public class IteratorUtils {
++    // validation is done in this class in certain cases because the
++    // public classes allow invalid states
++
++    /**
++     * An iterator over no elements.
++     * <p/>
++     * WARNING: This constant is binary incompatible with Commons Collections 2.1 and 2.1.1.
++     * Use <code>EmptyIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
++     */
++    public static final ResettableIterator EMPTY_ITERATOR = EmptyIterator.RESETTABLE_INSTANCE;
++    /**
++     * A list iterator over no elements.
++     * <p/>
++     * WARNING: This constant is binary incompatible with Commons Collections 2.1 and 2.1.1.
++     * Use <code>EmptyListIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
++     */
++    public static final ResettableListIterator EMPTY_LIST_ITERATOR = EmptyListIterator.RESETTABLE_INSTANCE;
++    /**
++     * An ordered iterator over no elements.
++     */
++    public static final OrderedIterator EMPTY_ORDERED_ITERATOR = EmptyOrderedIterator.INSTANCE;
++    /**
++     * A map iterator over no elements.
++     */
++    public static final MapIterator EMPTY_MAP_ITERATOR = EmptyMapIterator.INSTANCE;
++    /**
++     * An ordered map iterator over no elements.
++     */
++    public static final OrderedMapIterator EMPTY_ORDERED_MAP_ITERATOR = EmptyOrderedMapIterator.INSTANCE;
++
++    /**
++     * IteratorUtils is not normally instantiated.
++     */
++    public IteratorUtils() {
++    }
++
++    // Empty
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an empty iterator.
++     * <p/>
++     * This iterator is a valid iterator object that will iterate over
++     * nothing.
++     * <p/>
++     * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
++     * Use <code>EmptyIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
++     *
++     * @return an iterator over nothing
++     */
++    public static ResettableIterator emptyIterator() {
++        return EMPTY_ITERATOR;
++    }
++
++    /**
++     * Gets an empty list iterator.
++     * <p/>
++     * This iterator is a valid list iterator object that will iterate
++     * over nothing.
++     * <p/>
++     * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
++     * Use <code>EmptyListIterator.INSTANCE</code> for compatability with Commons Collections 2.1.1.
++     *
++     * @return a list iterator over nothing
++     */
++    public static ResettableListIterator emptyListIterator() {
++        return EMPTY_LIST_ITERATOR;
++    }
++
++    /**
++     * Gets an empty ordered iterator.
++     * <p/>
++     * This iterator is a valid iterator object that will iterate
++     * over nothing.
++     *
++     * @return an ordered iterator over nothing
++     */
++    public static OrderedIterator emptyOrderedIterator() {
++        return EMPTY_ORDERED_ITERATOR;
++    }
++
++    /**
++     * Gets an empty map iterator.
++     * <p/>
++     * This iterator is a valid map iterator object that will iterate
++     * over nothing.
++     *
++     * @return a map iterator over nothing
++     */
++    public static MapIterator emptyMapIterator() {
++        return EMPTY_MAP_ITERATOR;
++    }
++
++    /**
++     * Gets an empty ordered map iterator.
++     * <p/>
++     * This iterator is a valid map iterator object that will iterate
++     * over nothing.
++     *
++     * @return a map iterator over nothing
++     */
++    public static OrderedMapIterator emptyOrderedMapIterator() {
++        return EMPTY_ORDERED_MAP_ITERATOR;
++    }
++
++    // Singleton
++    //-----------------------------------------------------------------------
++    /**
++     * Gets a singleton iterator.
++     * <p/>
++     * This iterator is a valid iterator object that will iterate over
++     * the specified object.
++     * <p/>
++     * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
++     * Use <code>new SingletonIterator(object)</code> for compatability.
++     *
++     * @param object the single object over which to iterate
++     * @return a singleton iterator over the object
++     */
++    public static <E> ResettableIterator<E> singletonIterator(E object) {
++        return new SingletonIterator<E>(object);
++    }
++
++    /**
++     * Gets a singleton list iterator.
++     * <p/>
++     * This iterator is a valid list iterator object that will iterate over
++     * the specified object.
++     *
++     * @param object the single object over which to iterate
++     * @return a singleton list iterator over the object
++     */
++    public static <E> ListIterator<E> singletonListIterator(E object) {
++        return new SingletonListIterator<E>(object);
++    }
++
++    // Arrays
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator over an object array.
++     * <p/>
++     * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
++     * Use <code>new ArrayIterator(array)</code> for compatability.
++     *
++     * @param array the array over which to iterate
++     * @return an iterator over the array
++     * @throws NullPointerException if array is null
++     */
++    public static <E> ResettableIterator<E> arrayIterator(E[] array) {
++        return new ObjectArrayIterator<E>(array);
++    }
++
++    /**
++     * Gets an iterator over an object or primitive array.
++     * <p/>
++     * This method will handle primitive arrays as well as object arrays.
++     * The primitives will be wrapped in the appropriate wrapper class.
++     *
++     * @param array the array over which to iterate
++     * @return an iterator over the array
++     * @throws IllegalArgumentException if the array is not an array
++     * @throws NullPointerException     if array is null
++     */
++    public static <E> ResettableIterator<E> arrayIterator(Object array) {
++        return new ArrayIterator<E>(array);
++    }
++
++    /**
++     * Gets an iterator over the end part of an object array.
++     * <p/>
++     * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
++     * Use <code>new ArrayIterator(array,start)</code> for compatability.
++     *
++     * @param array the array over which to iterate
++     * @param start the index to start iterating at
++     * @return an iterator over part of the array
++     * @throws IndexOutOfBoundsException if start is less than zero or greater
++     *                                   than the length of the array
++     * @throws NullPointerException      if array is null
++     */
++    public static <E> ResettableIterator<E> arrayIterator(E[] array, int start) {
++        return new ObjectArrayIterator<E>(array, start);
++    }
++
++    /**
++     * Gets an iterator over the end part of an object or primitive array.
++     * <p/>
++     * This method will handle primitive arrays as well as object arrays.
++     * The primitives will be wrapped in the appropriate wrapper class.
++     *
++     * @param array the array over which to iterate
++     * @param start the index to start iterating at
++     * @return an iterator over part of the array
++     * @throws IllegalArgumentException  if the array is not an array
++     * @throws IndexOutOfBoundsException if start is less than zero or greater
++     *                                   than the length of the array
++     * @throws NullPointerException      if array is null
++     */
++    public static <E> ResettableIterator<E> arrayIterator(Object array, int start) {
++        return new ArrayIterator<E>(array, start);
++    }
++
++    /**
++     * Gets an iterator over part of an object array.
++     * <p/>
++     * WARNING: This method is binary incompatible with Commons Collections 2.1 and 2.1.1.
++     * Use <code>new ArrayIterator(array,start,end)</code> for compatability.
++     *
++     * @param array the array over which to iterate
++     * @param start the index to start iterating at
++     * @param end   the index to finish iterating at
++     * @return an iterator over part of the array
++     * @throws IndexOutOfBoundsException if array bounds are invalid
++     * @throws IllegalArgumentException  if end is before start
++     * @throws NullPointerException      if array is null
++     */
++    public static <E> ResettableIterator<E> arrayIterator(E[] array, int start, int end) {
++        return new ObjectArrayIterator<E>(array, start, end);
++    }
++
++    /**
++     * Gets an iterator over part of an object or primitive array.
++     * <p/>
++     * This method will handle primitive arrays as well as object arrays.
++     * The primitives will be wrapped in the appropriate wrapper class.
++     *
++     * @param array the array over which to iterate
++     * @param start the index to start iterating at
++     * @param end   the index to finish iterating at
++     * @return an iterator over part of the array
++     * @throws IllegalArgumentException  if the array is not an array
++     * @throws IndexOutOfBoundsException if array bounds are invalid
++     * @throws IllegalArgumentException  if end is before start
++     * @throws NullPointerException      if array is null
++     */
++    public static <E> ResettableIterator<E> arrayIterator(Object array, int start, int end) {
++        return new ArrayIterator<E>(array, start, end);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets a list iterator over an object array.
++     *
++     * @param array the array over which to iterate
++     * @return a list iterator over the array
++     * @throws NullPointerException if array is null
++     */
++    public static <E> ResettableListIterator<E> arrayListIterator(E[] array) {
++        return new ObjectArrayListIterator(array);
++    }
++
++    /**
++     * Gets a list iterator over an object or primitive array.
++     * <p/>
++     * This method will handle primitive arrays as well as object arrays.
++     * The primitives will be wrapped in the appropriate wrapper class.
++     *
++     * @param array the array over which to iterate
++     * @return a list iterator over the array
++     * @throws IllegalArgumentException if the array is not an array
++     * @throws NullPointerException     if array is null
++     */
++    public static <E> ResettableListIterator<E> arrayListIterator(Object array) {
++        return new ArrayListIterator<E>(array);
++    }
++
++    /**
++     * Gets a list iterator over the end part of an object array.
++     *
++     * @param array the array over which to iterate
++     * @param start the index to start iterating at
++     * @return a list iterator over part of the array
++     * @throws IndexOutOfBoundsException if start is less than zero
++     * @throws NullPointerException      if array is null
++     */
++    public static <E> ResettableListIterator<E> arrayListIterator(E[] array, int start) {
++        return new ObjectArrayListIterator<E>(array, start);
++    }
++
++    /**
++     * Gets a list iterator over the end part of an object or primitive array.
++     * <p/>
++     * This method will handle primitive arrays as well as object arrays.
++     * The primitives will be wrapped in the appropriate wrapper class.
++     *
++     * @param array the array over which to iterate
++     * @param start the index to start iterating at
++     * @return a list iterator over part of the array
++     * @throws IllegalArgumentException  if the array is not an array
++     * @throws IndexOutOfBoundsException if start is less than zero
++     * @throws NullPointerException      if array is null
++     */
++    public static <E> ResettableListIterator<E> arrayListIterator(Object array, int start) {
++        return new ArrayListIterator<E>(array, start);
++    }
++
++    /**
++     * Gets a list iterator over part of an object array.
++     *
++     * @param array the array over which to iterate
++     * @param start the index to start iterating at
++     * @param end   the index to finish iterating at
++     * @return a list iterator over part of the array
++     * @throws IndexOutOfBoundsException if array bounds are invalid
++     * @throws IllegalArgumentException  if end is before start
++     * @throws NullPointerException      if array is null
++     */
++    public static <E> ResettableListIterator<E> arrayListIterator(E[] array, int start, int end) {
++        return new ObjectArrayListIterator<E>(array, start, end);
++    }
++
++    /**
++     * Gets a list iterator over part of an object or primitive array.
++     * <p/>
++     * This method will handle primitive arrays as well as object arrays.
++     * The primitives will be wrapped in the appropriate wrapper class.
++     *
++     * @param array the array over which to iterate
++     * @param start the index to start iterating at
++     * @param end   the index to finish iterating at
++     * @return a list iterator over part of the array
++     * @throws IllegalArgumentException  if the array is not an array
++     * @throws IndexOutOfBoundsException if array bounds are invalid
++     * @throws IllegalArgumentException  if end is before start
++     * @throws NullPointerException      if array is null
++     */
++    public static <E> ResettableListIterator<E> arrayListIterator(Object array, int start, int end) {
++        return new ArrayListIterator<E>(array, start, end);
++    }
++    
++    // Unmodifiable
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an immutable version of an {@link Iterator}. The returned object
++     * will always throw an {@link UnsupportedOperationException} for
++     * the {@link Iterator#remove} method.
++     *
++     * @param iterator the iterator to make immutable
++     * @return an immutable version of the iterator
++     */
++    public static <E> Iterator<E> unmodifiableIterator(Iterator<E> iterator) {
++        return UnmodifiableIterator.decorate(iterator);
++    }
++
++    /**
++     * Gets an immutable version of a {@link ListIterator}. The returned object
++     * will always throw an {@link UnsupportedOperationException} for
++     * the {@link Iterator#remove}, {@link ListIterator#add} and
++     * {@link ListIterator#set} methods.
++     *
++     * @param listIterator the iterator to make immutable
++     * @return an immutable version of the iterator
++     */
++    public static <E> ListIterator<E> unmodifiableListIterator(ListIterator<E> listIterator) {
++        return UnmodifiableListIterator.decorate(listIterator);
++    }
++
++    /**
++     * Gets an immutable version of a {@link MapIterator}. The returned object
++     * will always throw an {@link UnsupportedOperationException} for
++     * the {@link Iterator#remove}, {@link MapIterator#setValue(Object)} methods.
++     *
++     * @param mapIterator the iterator to make immutable
++     * @return an immutable version of the iterator
++     */
++    public static <K,V> MapIterator<K, V> unmodifiableMapIterator(MapIterator<K, V> mapIterator) {
++        return UnmodifiableMapIterator.decorate(mapIterator);
++    }
++
++    // Chained
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator that iterates through two {@link Iterator}s
++     * one after another.
++     *
++     * @param iterator1 the first iterators to use, not null
++     * @param iterator2 the first iterators to use, not null
++     * @return a combination iterator over the iterators
++     * @throws NullPointerException if either iterator is null
++     */
++    public static <E> Iterator<E> chainedIterator(Iterator<E> iterator1, Iterator<E> iterator2) {
++        return new IteratorChain<E>(iterator1, iterator2);
++    }
++
++    /**
++     * Gets an iterator that iterates through an array of {@link Iterator}s
++     * one after another.
++     *
++     * @param iterators the iterators to use, not null or empty or contain nulls
++     * @return a combination iterator over the iterators
++     * @throws NullPointerException if iterators array is null or contains a null
++     */
++    public static <E> Iterator<E> chainedIterator(Iterator<E>[] iterators) {
++        return new IteratorChain<E>(iterators);
++    }
++
++    /**
++     * Gets an iterator that iterates through a collections15 of {@link Iterator}s
++     * one after another.
++     *
++     * @param iterators the iterators to use, not null or empty or contain nulls
++     * @return a combination iterator over the iterators
++     * @throws NullPointerException if iterators collection is null or contains a null
++     * @throws ClassCastException   if the iterators collection contains the wrong object type
++     */
++    public static <E> Iterator<E> chainedIterator(Collection<Iterator<? extends E>> iterators) {
++        return new IteratorChain<E>(iterators);
++    }
++
++    // Collated
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator that provides an ordered iteration over the elements
++     * contained in a collection of ordered {@link Iterator}s.
++     * <p/>
++     * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
++     * the {@link Iterator#next()} method will return the lesser of
++     * <code>A.next()</code> and <code>B.next()</code>.
++     * <p/>
++     * The comparator is optional. If null is specified then natural order is used.
++     *
++     * @param comparator the comparator to use, may be null for natural order
++     * @param iterator1  the first iterators to use, not null
++     * @param iterator2  the first iterators to use, not null
++     * @return a combination iterator over the iterators
++     * @throws NullPointerException if either iterator is null
++     */
++    public static <E> Iterator<E> collatedIterator(Comparator<? super E> comparator, Iterator<? extends E> iterator1, Iterator<? extends E> iterator2) {
++        return new CollatingIterator<E>(comparator, iterator1, iterator2);
++    }
++
++    /**
++     * Gets an iterator that provides an ordered iteration over the elements
++     * contained in an array of {@link Iterator}s.
++     * <p/>
++     * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
++     * the {@link Iterator#next()} method will return the lesser of
++     * <code>A.next()</code> and <code>B.next()</code> and so on.
++     * <p/>
++     * The comparator is optional. If null is specified then natural order is used.
++     *
++     * @param comparator the comparator to use, may be null for natural order
++     * @param iterators  the iterators to use, not null or empty or contain nulls
++     * @return a combination iterator over the iterators
++     * @throws NullPointerException if iterators array is null or contains a null
++     */
++    public static <E> Iterator<E> collatedIterator(Comparator<? super E> comparator, Iterator<? extends E>[] iterators) {
++        return new CollatingIterator<E>(comparator, iterators);
++    }
++
++    /**
++     * Gets an iterator that provides an ordered iteration over the elements
++     * contained in a collection of {@link Iterator}s.
++     * <p/>
++     * Given two ordered {@link Iterator}s <code>A</code> and <code>B</code>,
++     * the {@link Iterator#next()} method will return the lesser of
++     * <code>A.next()</code> and <code>B.next()</code> and so on.
++     * <p/>
++     * The comparator is optional. If null is specified then natural order is used.
++     *
++     * @param comparator the comparator to use, may be null for natural order
++     * @param iterators  the iterators to use, not null or empty or contain nulls
++     * @return a combination iterator over the iterators
++     * @throws NullPointerException if iterators collection is null or contains a null
++     * @throws ClassCastException   if the iterators collection contains the wrong object type
++     */
++    public static <E> Iterator<E> collatedIterator(Comparator<? super E> comparator, Collection<Iterator<? extends E>> iterators) {
++        return new CollatingIterator<E>(comparator, iterators);
++    }
++    
++    // Object Graph
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator that operates over an object graph.
++     * <p/>
++     * This iterator can extract multiple objects from a complex tree-like object graph.
++     * The iteration starts from a single root object.
++     * It uses a <code>Transformer</code> to extract the iterators and elements.
++     * Its main benefit is that no intermediate <code>List</code> is created.
++     * <p/>
++     * For example, consider an object graph:
++     * <pre>
++     *                 |- Branch -- Leaf
++     *                 |         \- Leaf
++     *         |- Tree |         /- Leaf
++     *         |       |- Branch -- Leaf
++     *  Forest |                 \- Leaf
++     *         |       |- Branch -- Leaf
++     *         |       |         \- Leaf
++     *         |- Tree |         /- Leaf
++     *                 |- Branch -- Leaf
++     *                 |- Branch -- Leaf</pre>
++     * The following <code>Transformer</code>, used in this class, will extract all
++     * the Leaf objects without creating a combined intermediate list:
++     * <pre>
++     * public Object transform(Object input) {
++     *   if (input instanceof Forest) {
++     *     return ((Forest) input).treeIterator();
++     *   }
++     *   if (input instanceof Tree) {
++     *     return ((Tree) input).branchIterator();
++     *   }
++     *   if (input instanceof Branch) {
++     *     return ((Branch) input).leafIterator();
++     *   }
++     *   if (input instanceof Leaf) {
++     *     return input;
++     *   }
++     *   throw new ClassCastException();
++     * }</pre>
++     * <p/>
++     * Internally, iteration starts from the root object. When next is called,
++     * the transformer is called to examine the object. The transformer will return
++     * either an iterator or an object. If the object is an Iterator, the next element
++     * from that iterator is obtained and the process repeats. If the element is an object
++     * it is returned.
++     * <p/>
++     * Under many circumstances, linking Iterators together in this manner is
++     * more efficient (and convenient) than using nested for loops to extract a list.
++     *
++     * @param root        the root object to start iterating from, null results in an empty iterator
++     * @param transformer the transformer to use, see above, null uses no effect transformer
++     * @return a new object graph iterator
++     * @since Commons Collections 3.1
++     */
++    public static Iterator objectGraphIterator(Object root, Transformer transformer) {
++        return new ObjectGraphIterator(root, transformer);
++    }
++    
++    // Transformed
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator that transforms the elements of another iterator.
++     * <p/>
++     * The transformation occurs during the next() method and the underlying
++     * iterator is unaffected by the transformation.
++     *
++     * @param iterator  the iterator to use, not null
++     * @param transform the transform to use, not null
++     * @return a new transforming iterator
++     * @throws NullPointerException if either parameter is null
++     */
++    public static <I,O> Iterator<O> transformedIterator(Iterator<I> iterator, Transformer<I, O> transform) {
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        if (transform == null) {
++            throw new NullPointerException("Transformer must not be null");
++        }
++        return new TransformIterator<I, O>(iterator, transform);
++    }
++    
++    // Filtered
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator that filters another iterator.
++     * <p/>
++     * The returned iterator will only return objects that match the specified
++     * filtering predicate.
++     *
++     * @param iterator  the iterator to use, not null
++     * @param predicate the predicate to use as a filter, not null
++     * @return a new filtered iterator
++     * @throws NullPointerException if either parameter is null
++     */
++    public static <E> Iterator<E> filteredIterator(Iterator<E> iterator, Predicate<? super E> predicate) {
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        if (predicate == null) {
++            throw new NullPointerException("Predicate must not be null");
++        }
++        return new FilterIterator<E>(iterator, predicate);
++    }
++
++    /**
++     * Gets a list iterator that filters another list iterator.
++     * <p/>
++     * The returned iterator will only return objects that match the specified
++     * filtering predicate.
++     *
++     * @param listIterator the list iterator to use, not null
++     * @param predicate    the predicate to use as a filter, not null
++     * @return a new filtered iterator
++     * @throws NullPointerException if either parameter is null
++     */
++    public static <E> ListIterator<E> filteredListIterator(ListIterator<E> listIterator, Predicate<? super E> predicate) {
++        if (listIterator == null) {
++            throw new NullPointerException("ListIterator must not be null");
++        }
++        if (predicate == null) {
++            throw new NullPointerException("Predicate must not be null");
++        }
++        return new FilterListIterator<E>(listIterator, predicate);
++    }
++    
++    // Looping
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator that loops continuously over the supplied collection.
++     * <p/>
++     * The iterator will only stop looping if the remove method is called
++     * enough times to empty the collection, or if the collection is empty
++     * to start with.
++     *
++     * @param coll the collection to iterate over, not null
++     * @return a new looping iterator
++     * @throws NullPointerException if the collection is null
++     */
++    public static <E> ResettableIterator<E> loopingIterator(Collection<E> coll) {
++        if (coll == null) {
++            throw new NullPointerException("Collection must not be null");
++        }
++        return new LoopingIterator<E>(coll);
++    }
++    
++    // Views
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator that provides an iterator view of the given enumeration.
++     *
++     * @param enumeration the enumeration to use
++     * @return a new iterator
++     */
++    public static <E> Iterator<E> asIterator(Enumeration<E> enumeration) {
++        if (enumeration == null) {
++            throw new NullPointerException("Enumeration must not be null");
++        }
++        return new EnumerationIterator<E>(enumeration);
++    }
++
++    /**
++     * Gets an iterator that provides an iterator view of the given enumeration
++     * that will remove elements from the specified collection.
++     *
++     * @param enumeration      the enumeration to use
++     * @param removeCollection the collection to remove elements from
++     * @return a new iterator
++     */
++    public static <E> Iterator<E> asIterator(Enumeration<E> enumeration, Collection<E> removeCollection) {
++        if (enumeration == null) {
++            throw new NullPointerException("Enumeration must not be null");
++        }
++        if (removeCollection == null) {
++            throw new NullPointerException("Collection must not be null");
++        }
++        return new EnumerationIterator<E>(enumeration, removeCollection);
++    }
++
++    /**
++     * Gets an enumeration that wraps an iterator.
++     *
++     * @param iterator the iterator to use, not null
++     * @return a new enumeration
++     * @throws NullPointerException if iterator is null
++     */
++    public static <E> Enumeration<E> asEnumeration(Iterator<E> iterator) {
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        return new IteratorEnumeration<E>(iterator);
++    }
++
++    /**
++     * Gets a list iterator based on a simple iterator.
++     * <p/>
++     * As the wrapped Iterator is traversed, a LinkedList of its values is
++     * cached, permitting all required operations of ListIterator.
++     *
++     * @param iterator the iterator to use, not null
++     * @return a new iterator
++     * @throws NullPointerException if iterator parameter is null
++     */
++    public static <E> ListIterator<E> toListIterator(Iterator<E> iterator) {
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        return new ListIteratorWrapper<E>(iterator);
++    }
++
++    /**
++     * Gets an array based on an iterator.
++     * <p/>
++     * As the wrapped Iterator is traversed, an ArrayList of its values is
++     * created. At the end, this is converted to an array.
++     *
++     * @param iterator the iterator to use, not null
++     * @return an array of the iterator contents
++     * @throws NullPointerException if iterator parameter is null
++     */
++    public static <E> E[] toArray(Iterator<E> iterator) {
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        List<E> list = toList(iterator, 100);
++        return (E[]) list.toArray();
++    }
++
++    /**
++     * Gets an array based on an iterator.
++     * <p/>
++     * As the wrapped Iterator is traversed, an ArrayList of its values is
++     * created. At the end, this is converted to an array.
++     *
++     * @param iterator   the iterator to use, not null
++     * @param arrayClass the class of array to create
++     * @return an array of the iterator contents
++     * @throws NullPointerException if iterator parameter is null
++     * @throws NullPointerException if arrayClass is null
++     * @throws ClassCastException   if the arrayClass is invalid
++     */
++    public static <E> E[] toArray(Iterator<E> iterator, Class<E> arrayClass) {
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        if (arrayClass == null) {
++            throw new NullPointerException("Array class must not be null");
++        }
++        List<E> list = toList(iterator, 100);
++        return list.toArray((E[]) Array.newInstance(arrayClass, list.size()));
++    }
++
++    /**
++     * Gets a list based on an iterator.
++     * <p/>
++     * As the wrapped Iterator is traversed, an ArrayList of its values is
++     * created. At the end, the list is returned.
++     *
++     * @param iterator the iterator to use, not null
++     * @return a list of the iterator contents
++     * @throws NullPointerException if iterator parameter is null
++     */
++    public static <E> List<E> toList(Iterator<E> iterator) {
++        return toList(iterator, 10);
++    }
++
++    /**
++     * Gets a list based on an iterator.
++     * <p/>
++     * As the wrapped Iterator is traversed, an ArrayList of its values is
++     * created. At the end, the list is returned.
++     *
++     * @param iterator      the iterator to use, not null
++     * @param estimatedSize the initial size of the ArrayList
++     * @return a list of the iterator contents
++     * @throws NullPointerException     if iterator parameter is null
++     * @throws IllegalArgumentException if the size is less than 1
++     */
++    public static <E> List<E> toList(Iterator<E> iterator, int estimatedSize) {
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        if (estimatedSize < 1) {
++            throw new IllegalArgumentException("Estimated size must be greater than 0");
++        }
++        List<E> list = new ArrayList<E>(estimatedSize);
++        while (iterator.hasNext()) {
++            list.add(iterator.next());
++        }
++        return list;
++    }
++
++    /**
++     * Gets a suitable Iterator for the given object.
++     * <p/>
++     * This method can handles objects as follows
++     * <ul>
++     * <li>null - empty iterator
++     * <li>Iterator - returned directly
++     * <li>Enumeration - wrapped
++     * <li>Collection - iterator from collection returned
++     * <li>Map - values iterator returned
++     * <li>Dictionary - values (elements) enumeration returned as iterator
++     * <li>array - iterator over array returned
++     * <li>object with iterator() public method accessed by reflection
++     * <li>object - singleton iterator
++     * </ul>
++     *
++     * @param obj the object to convert to an iterator
++     * @return a suitable iterator, never null
++     */
++    public static Iterator getIterator(Object obj) {
++        if (obj == null) {
++            return emptyIterator();
++
++        } else if (obj instanceof Iterator) {
++            return (Iterator) obj;
++
++        } else if (obj instanceof Collection) {
++            return ((Collection) obj).iterator();
++
++        } else if (obj instanceof Object[]) {
++            return new ObjectArrayIterator((Object[]) obj);
++
++        } else if (obj instanceof Enumeration) {
++            return new EnumerationIterator((Enumeration) obj);
++
++        } else if (obj instanceof Map) {
++            return ((Map) obj).values().iterator();
++
++        } else if (obj instanceof Dictionary) {
++            return new EnumerationIterator(((Dictionary) obj).elements());
++
++        } else if (obj != null && obj.getClass().isArray()) {
++            return new ArrayIterator(obj);
++
++        } else {
++            try {
++                Method method = obj.getClass().getMethod("iterator", null);
++                if (Iterator.class.isAssignableFrom(method.getReturnType())) {
++                    Iterator it = (Iterator) method.invoke(obj, null);
++                    if (it != null) {
++                        return it;
++                    }
++                }
++            } catch (Exception ex) {
++                // ignore
++            }
++            return singletonIterator(obj);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/KeyValue.java
+@@ -0,0 +1,46 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++/**
++ * Defines a simple key value pair.
++ * <p/>
++ * A Map Entry has considerable additional semantics over and above a simple
++ * key-value pair. This interface defines the minimum key value, with just the
++ * two get methods.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface KeyValue <K,V> {
++
++    /**
++     * Gets the key from the pair.
++     *
++     * @return the key
++     */
++    K getKey();
++
++    /**
++     * Gets the value from the pair.
++     *
++     * @return the value
++     */
++    V getValue();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/ListUtils.java
+@@ -0,0 +1,345 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.list.*;
++
++import java.util.*;
++
++/**
++ * Provides utility methods and decorators for {@link List} instances.
++ *
++ * @author Federico Barbieri
++ * @author Peter Donald
++ * @author Paul Jack
++ * @author Stephen Colebourne
++ * @author Neil O'Toole
++ * @author Matt Hall, John Watkinson, Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 1.0
++ */
++public class ListUtils {
++
++    /**
++     * An empty unmodifiable list.
++     * This uses the {@link Collections Collections} implementation
++     * and is provided for completeness.
++     */
++    public static final List EMPTY_LIST = Collections.EMPTY_LIST;
++
++    /**
++     * <code>ListUtils</code> should not normally be instantiated.
++     */
++    public ListUtils() {
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a new list containing all elements that are contained in
++     * both given lists.
++     *
++     * @param list1 the first list
++     * @param list2 the second list
++     * @return the intersection of those two lists
++     * @throws NullPointerException if either list is null
++     */
++    public static <E> List<E> intersection(final List<? extends E> list1, final List<? extends E> list2) {
++        final ArrayList<E> result = new ArrayList<E>();
++        final Iterator<? extends E> iterator = list2.iterator();
++
++        while (iterator.hasNext()) {
++            final E o = iterator.next();
++
++            if (list1.contains(o)) {
++                result.add(o);
++            }
++        }
++
++        return result;
++    }
++
++    /**
++     * Subtracts all elements in the second list from the first list,
++     * placing the results in a new list.
++     * <p/>
++     * This differs from {@link List#removeAll(Collection)} in that
++     * cardinality is respected; if <Code>list1</Code> contains two
++     * occurrences of <Code>null</Code> and <Code>list2</Code> only
++     * contains one occurrence, then the returned list will still contain
++     * one occurrence.
++     *
++     * @param list1 the list to subtract from
++     * @param list2 the list to subtract
++     * @return a new list containing the results
++     * @throws NullPointerException if either list is null
++     */
++    public static <E> List<E> subtract(final List<? extends E> list1, final List<? extends E> list2) {
++        final ArrayList<E> result = new ArrayList<E>(list1);
++        final Iterator<? extends E> iterator = list2.iterator();
++
++        while (iterator.hasNext()) {
++            result.remove(iterator.next());
++        }
++
++        return result;
++    }
++
++    /**
++     * Returns the sum of the given lists.  This is their intersection
++     * subtracted from their union.
++     *
++     * @param list1 the first list
++     * @param list2 the second list
++     * @return a new list containing the sum of those lists
++     * @throws NullPointerException if either list is null
++     */
++    public static <E> List<E> sum(final List<? extends E> list1, final List<? extends E> list2) {
++        return subtract(union(list1, list2), intersection(list1, list2));
++    }
++
++    /**
++     * Returns a new list containing the second list appended to the
++     * first list.  The {@link List#addAll(Collection)} operation is
++     * used to append the two given lists into a new list.
++     *
++     * @param list1 the first list
++     * @param list2 the second list
++     * @return a new list containing the union of those lists
++     * @throws NullPointerException if either list is null
++     */
++    public static <E> List<E> union(final List<? extends E> list1, final List<? extends E> list2) {
++        final ArrayList<E> result = new ArrayList<E>(list1);
++        result.addAll(list2);
++        return result;
++    }
++
++    /**
++     * Tests two lists for value-equality as per the equality contract in
++     * {@link java.util.List#equals(java.lang.Object)}.
++     * <p/>
++     * This method is useful for implementing <code>List</code> when you cannot
++     * extend AbstractList. The method takes Collection instances to enable other
++     * collection types to use the List implementation algorithm.
++     * <p/>
++     * The relevant text (slightly paraphrased as this is a static method) is:
++     * <blockquote>
++     * Compares the two list objects for equality.  Returns
++     * <tt>true</tt> if and only if both
++     * lists have the same size, and all corresponding pairs of elements in
++     * the two lists are <i>equal</i>.  (Two elements <tt>e1</tt> and
++     * <tt>e2</tt> are <i>equal</i> if <tt>(e1==null ? e2==null :
++     * e1.equals(e2))</tt>.)  In other words, two lists are defined to be
++     * equal if they contain the same elements in the same order.  This
++     * definition ensures that the equals method works properly across
++     * different implementations of the <tt>List</tt> interface.
++     * </blockquote>
++     * <p/>
++     * <b>Note:</b> The behaviour of this method is undefined if the lists are
++     * modified during the equals comparison.
++     *
++     * @param list1 the first list, may be null
++     * @param list2 the second list, may be null
++     * @return whether the lists are equal by value comparison
++     * @see java.util.List
++     */
++    public static <E> boolean isEqualList(final Collection<? extends E> list1, final Collection<? extends E> list2) {
++        if (list1 == list2) {
++            return true;
++        }
++        if (list1 == null || list2 == null || list1.size() != list2.size()) {
++            return false;
++        }
++
++        Iterator<? extends E> it1 = list1.iterator();
++        Iterator<? extends E> it2 = list2.iterator();
++        E obj1 = null;
++        E obj2 = null;
++
++        while (it1.hasNext() && it2.hasNext()) {
++            obj1 = it1.next();
++            obj2 = it2.next();
++
++            if (!(obj1 == null ? obj2 == null : obj1.equals(obj2))) {
++                return false;
++            }
++        }
++
++        return !(it1.hasNext() || it2.hasNext());
++    }
++
++    /**
++     * Generates a hash code using the algorithm specified in
++     * {@link java.util.List#hashCode()}.
++     * <p/>
++     * This method is useful for implementing <code>List</code> when you cannot
++     * extend AbstractList. The method takes Collection instances to enable other
++     * collection types to use the List implementation algorithm.
++     *
++     * @param list the list to generate the hashCode for, may be null
++     * @return the hash code
++     * @see java.util.List#hashCode()
++     */
++    public static int hashCodeForList(final Collection list) {
++        if (list == null) {
++            return 0;
++        }
++        int hashCode = 1;
++        Iterator it = list.iterator();
++        Object obj = null;
++
++        while (it.hasNext()) {
++            obj = it.next();
++            hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
++        }
++        return hashCode;
++    }   
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a synchronized list backed by the given list.
++     * <p/>
++     * You must manually synchronize on the returned buffer's iterator to
++     * avoid non-deterministic behavior:
++     * <p/>
++     * <pre>
++     * List list = ListUtils.synchronizedList(myList);
++     * synchronized (list) {
++     *     Iterator i = list.iterator();
++     *     while (i.hasNext()) {
++     *         process (i.next());
++     *     }
++     * }
++     * </pre>
++     * <p/>
++     * This method uses the implementation in the decorators subpackage.
++     *
++     * @param list the list to synchronize, must not be null
++     * @return a synchronized list backed by the given list
++     * @throws IllegalArgumentException if the list is null
++     */
++    public static <E> List<E> synchronizedList(List<E> list) {
++        return SynchronizedList.decorate(list);
++    }
++
++    /**
++     * Returns an unmodifiable list backed by the given list.
++     * <p/>
++     * This method uses the implementation in the decorators subpackage.
++     *
++     * @param list the list to make unmodifiable, must not be null
++     * @return an unmodifiable list backed by the given list
++     * @throws IllegalArgumentException if the list is null
++     */
++    public static <E> List<E> unmodifiableList(List<E> list) {
++        return UnmodifiableList.decorate(list);
++    }
++
++    /**
++     * Returns a predicated (validating) list backed by the given list.
++     * <p/>
++     * Only objects that pass the test in the given predicate can be added to the list.
++     * Trying to add an invalid object results in an IllegalArgumentException.
++     * It is important not to use the original list after invoking this method,
++     * as it is a backdoor for adding invalid objects.
++     *
++     * @param list      the list to predicate, must not be null
++     * @param predicate the predicate for the list, must not be null
++     * @return a predicated list backed by the given list
++     * @throws IllegalArgumentException if the List or Predicate is null
++     */
++    public static <E> List<E> predicatedList(List<E> list, Predicate<? super E> predicate) {
++        return PredicatedList.decorate(list, predicate);
++    }
++
++    /**
++     * Returns a typed list backed by the given list.
++     * <p/>
++     * Only objects of the specified type can be added to the list.
++     *
++     * @param list the list to limit to a specific type, must not be null
++     * @param type the type of objects which may be added to the list
++     * @return a typed list backed by the specified list
++     * @deprecated Java generics makes this method obsolete.
++     */
++    public static <E> List<E> typedList(List<E> list, Class<E> type) {
++        return TypedList.decorate(list, type);
++    }
++
++    /**
++     * Returns a transformed list backed by the given list.
++     * <p/>
++     * Each object is passed through the transformer as it is added to the
++     * List. It is important not to use the original list after invoking this
++     * method, as it is a backdoor for adding untransformed objects.
++     *
++     * @param list        the list to predicate, must not be null
++     * @param transformer the transformer for the list, must not be null
++     * @return a transformed list backed by the given list
++     * @throws IllegalArgumentException if the List or Transformer is null
++     */
++    public static <I,O> List<O> transformedList(List<I> list, Transformer<? super I, ? extends O> transformer) {
++        return TransformedList.decorate(list, transformer);
++    }
++
++    /**
++     * Returns a "lazy" list whose elements will be created on demand.
++     * <p/>
++     * When the index passed to the returned list's {@link List#get(int) get}
++     * method is greater than the list's size, then the factory will be used
++     * to create a new object and that object will be inserted at that index.
++     * <p/>
++     * For instance:
++     * <p/>
++     * <pre>
++     * Factory factory = new Factory() {
++     *     public Object create() {
++     *         return new Date();
++     *     }
++     * }
++     * List lazy = ListUtils.lazyList(new ArrayList(), factory);
++     * Object obj = lazy.get(3);
++     * </pre>
++     * <p/>
++     * After the above code is executed, <code>obj</code> will contain
++     * a new <code>Date</code> instance.  Furthermore, that <code>Date</code>
++     * instance is the fourth element in the list.  The first, second,
++     * and third element are all set to <code>null</code>.
++     *
++     * @param list    the list to make lazy, must not be null
++     * @param factory the factory for creating new objects, must not be null
++     * @return a lazy list backed by the given list
++     * @throws IllegalArgumentException if the List or Factory is null
++     */
++    public static <E> List<E> lazyList(List<E> list, Factory<? extends E> factory) {
++        return LazyList.decorate(list, factory);
++    }
++
++    /**
++     * Returns a fixed-sized list backed by the given list.
++     * Elements may not be added or removed from the returned list, but
++     * existing elements can be changed (for instance, via the
++     * {@link List#set(int,Object)} method).
++     *
++     * @param list the list whose size to fix, must not be null
++     * @return a fixed-size list backed by that list
++     * @throws IllegalArgumentException if the List is null
++     */
++    public static <E> List<E> fixedSizeList(List<E> list) {
++        return FixedSizeList.decorate(list);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/MapIterator.java
+@@ -0,0 +1,109 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.Iterator;
++
++/**
++ * Defines an iterator that operates over a <code>Map</code>.
++ * <p/>
++ * This iterator is a special version designed for maps. It can be more
++ * efficient to use this rather than an entry set iterator where the option
++ * is available, and it is certainly more convenient.
++ * <p/>
++ * A map that provides this interface may not hold the data internally using
++ * Map Entry objects, thus this interface can avoid lots of object creation.
++ * <p/>
++ * In use, this iterator iterates through the keys in the map. After each call
++ * to <code>next()</code>, the <code>getValue()</code> method provides direct
++ * access to the value. The value can also be set using <code>setValue()</code>.
++ * <pre>
++ * MapIterator it = map.mapIterator();
++ * while (it.hasNext()) {
++ *   Object key = it.next();
++ *   Object value = it.getValue();
++ *   it.setValue(newValue);
++ * }
++ * </pre>
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface MapIterator <K,V> extends Iterator<K> {
++
++    /**
++     * Checks to see if there are more entries still to be iterated.
++     *
++     * @return <code>true</code> if the iterator has more elements
++     */
++    boolean hasNext();
++
++    /**
++     * Gets the next <em>key</em> from the <code>Map</code>.
++     *
++     * @return the next key in the iteration
++     * @throws java.util.NoSuchElementException
++     *          if the iteration is finished
++     */
++    K next();
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the current key, which is the key returned by the last call
++     * to <code>next()</code>.
++     *
++     * @return the current key
++     * @throws IllegalStateException if <code>next()</code> has not yet been called
++     */
++    K getKey();
++
++    /**
++     * Gets the current value, which is the value associated with the last key
++     * returned by <code>next()</code>.
++     *
++     * @return the current value
++     * @throws IllegalStateException if <code>next()</code> has not yet been called
++     */
++    V getValue();
++
++    //-----------------------------------------------------------------------
++    /**
++     * Removes the last returned key from the underlying <code>Map</code> (optional operation).
++     * <p/>
++     * This method can be called once per call to <code>next()</code>.
++     *
++     * @throws UnsupportedOperationException if remove is not supported by the map
++     * @throws IllegalStateException         if <code>next()</code> has not yet been called
++     * @throws IllegalStateException         if <code>remove()</code> has already been called
++     *                                       since the last call to <code>next()</code>
++     */
++    void remove();
++
++    /**
++     * Sets the value associated with the current key (optional operation).
++     *
++     * @param value the new value
++     * @return the previous value
++     * @throws UnsupportedOperationException if setValue is not supported by the map
++     * @throws IllegalStateException         if <code>next()</code> has not yet been called
++     * @throws IllegalStateException         if <code>remove()</code> has been called since the
++     *                                       last call to <code>next()</code>
++     */
++    V setValue(V value);
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/MapUtils.java
+@@ -0,0 +1,1354 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.map.*;
++
++import java.io.PrintStream;
++import java.text.NumberFormat;
++import java.text.ParseException;
++import java.util.*;
++
++/**
++ * Provides utility methods and decorators for
++ * {@link Map} and {@link SortedMap} instances.
++ * <p/>
++ * It contains various type safe methods
++ * as well as other useful features like deep copying.
++ * <p/>
++ * It also provides the following decorators:
++ * <p/>
++ * <ul>
++ * <li>{@link #fixedSizeMap(Map)}
++ * <li>{@link #fixedSizeSortedMap(SortedMap)}
++ * <li>{@link #lazyMap(Map,Factory)}
++ * <li>{@link #lazySortedMap(SortedMap,Factory)}
++ * <li>{@link #predicatedMap(Map,Predicate,Predicate)}
++ * <li>{@link #predicatedSortedMap(SortedMap,Predicate,Predicate)}
++ * <li>{@link #transformedMap(Map, Transformer, Transformer)}
++ * <li>{@link #transformedSortedMap(SortedMap, Transformer, Transformer)}
++ * <li>{@link #typedMap(Map, Class, Class)}
++ * <li>{@link #typedSortedMap(SortedMap, Class, Class)}
++ * </ul>
++ *
++ * @author <a href="mailto:jstrachan at apache.org">James Strachan</a>
++ * @author <a href="mailto:nissim at nksystems.com">Nissim Karpenstein</a>
++ * @author <a href="mailto:knielsen at apache.org">Kasper Nielsen</a>
++ * @author Paul Jack
++ * @author Stephen Colebourne
++ * @author Matthew Hawthorne
++ * @author Arun Mammen Thomas
++ * @author Janek Bogucki
++ * @author Max Rydahl Andersen
++ * @author Matt Hall, John Watkinson, <a href="mailto:equinus100 at hotmail.com">Ashwin S</a>
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 1.0
++ */
++public class MapUtils {
++
++    /**
++     * An empty unmodifiable map.
++     * This was not provided in JDK1.2.
++     */
++    public static final Map EMPTY_MAP = UnmodifiableMap.decorate(new HashMap(1));
++    /**
++     * An empty unmodifiable sorted map.
++     * This is not provided in the JDK.
++     */
++    public static final SortedMap EMPTY_SORTED_MAP = UnmodifiableSortedMap.decorate(new TreeMap());
++    /**
++     * String used to indent the verbose and debug Map prints.
++     */
++    private static final String INDENT_STRING = "    ";
++
++    /**
++     * <code>MapUtils</code> should not normally be instantiated.
++     */
++    public MapUtils() {
++    }    
++    
++    // Type safe getters
++    //-------------------------------------------------------------------------
++    /**
++     * Gets from a Map in a null-safe manner.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map, <code>null</code> if null map input
++     */
++    public static <K,V> V getObject(final Map<K, V> map, final K key) {
++        if (map != null) {
++            return map.get(key);
++        }
++        return null;
++    }
++
++    /**
++     * Gets a String from a Map in a null-safe manner.
++     * <p/>
++     * The String is obtained via <code>toString</code>.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a String, <code>null</code> if null map input
++     */
++    public static <K,V> String getString(final Map<K, V> map, final K key) {
++        if (map != null) {
++            V answer = map.get(key);
++            if (answer != null) {
++                return answer.toString();
++            }
++        }
++        return null;
++    }
++
++    /**
++     * Gets a Boolean from a Map in a null-safe manner.
++     * <p/>
++     * If the value is a <code>Boolean</code> it is returned directly.
++     * If the value is a <code>String</code> and it equals 'true' ignoring case
++     * then <code>true</code> is returned, otherwise <code>false</code>.
++     * If the value is a <code>Number</code> an integer zero value returns
++     * <code>false</code> and non-zero returns <code>true</code>.
++     * Otherwise, <code>null</code> is returned.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a Boolean, <code>null</code> if null map input
++     */
++    public static Boolean getBoolean(final Map map, final Object key) {
++        if (map != null) {
++            Object answer = map.get(key);
++            if (answer != null) {
++                if (answer instanceof Boolean) {
++                    return (Boolean) answer;
++
++                } else if (answer instanceof String) {
++                    return new Boolean((String) answer);
++
++                } else if (answer instanceof Number) {
++                    Number n = (Number) answer;
++                    return (n.intValue() != 0) ? Boolean.TRUE : Boolean.FALSE;
++                }
++            }
++        }
++        return null;
++    }
++
++    /**
++     * Gets a Number from a Map in a null-safe manner.
++     * <p/>
++     * If the value is a <code>Number</code> it is returned directly.
++     * If the value is a <code>String</code> it is converted using
++     * {@link NumberFormat#parse(String)} on the system default formatter
++     * returning <code>null</code> if the conversion fails.
++     * Otherwise, <code>null</code> is returned.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a Number, <code>null</code> if null map input
++     */
++    public static Number getNumber(final Map map, final Object key) {
++        if (map != null) {
++            Object answer = map.get(key);
++            if (answer != null) {
++                if (answer instanceof Number) {
++                    return (Number) answer;
++
++                } else if (answer instanceof String) {
++                    try {
++                        String text = (String) answer;
++                        return NumberFormat.getInstance().parse(text);
++
++                    } catch (ParseException e) {
++                        logInfo(e);
++                    }
++                }
++            }
++        }
++        return null;
++    }
++
++    /**
++     * Gets a Byte from a Map in a null-safe manner.
++     * <p/>
++     * The Byte is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a Byte, <code>null</code> if null map input
++     */
++    public static Byte getByte(final Map map, final Object key) {
++        Number answer = getNumber(map, key);
++        if (answer == null) {
++            return null;
++        } else if (answer instanceof Byte) {
++            return (Byte) answer;
++        }
++        return new Byte(answer.byteValue());
++    }
++
++    /**
++     * Gets a Short from a Map in a null-safe manner.
++     * <p/>
++     * The Short is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a Short, <code>null</code> if null map input
++     */
++    public static Short getShort(final Map map, final Object key) {
++        Number answer = getNumber(map, key);
++        if (answer == null) {
++            return null;
++        } else if (answer instanceof Short) {
++            return (Short) answer;
++        }
++        return new Short(answer.shortValue());
++    }
++
++    /**
++     * Gets a Integer from a Map in a null-safe manner.
++     * <p/>
++     * The Integer is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a Integer, <code>null</code> if null map input
++     */
++    public static Integer getInteger(final Map map, final Object key) {
++        Number answer = getNumber(map, key);
++        if (answer == null) {
++            return null;
++        } else if (answer instanceof Integer) {
++            return (Integer) answer;
++        }
++        return new Integer(answer.intValue());
++    }
++
++    /**
++     * Gets a Long from a Map in a null-safe manner.
++     * <p/>
++     * The Long is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a Long, <code>null</code> if null map input
++     */
++    public static Long getLong(final Map map, final Object key) {
++        Number answer = getNumber(map, key);
++        if (answer == null) {
++            return null;
++        } else if (answer instanceof Long) {
++            return (Long) answer;
++        }
++        return new Long(answer.longValue());
++    }
++
++    /**
++     * Gets a Float from a Map in a null-safe manner.
++     * <p/>
++     * The Float is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a Float, <code>null</code> if null map input
++     */
++    public static Float getFloat(final Map map, final Object key) {
++        Number answer = getNumber(map, key);
++        if (answer == null) {
++            return null;
++        } else if (answer instanceof Float) {
++            return (Float) answer;
++        }
++        return new Float(answer.floatValue());
++    }
++
++    /**
++     * Gets a Double from a Map in a null-safe manner.
++     * <p/>
++     * The Double is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a Double, <code>null</code> if null map input
++     */
++    public static Double getDouble(final Map map, final Object key) {
++        Number answer = getNumber(map, key);
++        if (answer == null) {
++            return null;
++        } else if (answer instanceof Double) {
++            return (Double) answer;
++        }
++        return new Double(answer.doubleValue());
++    }
++
++    /**
++     * Gets a Map from a Map in a null-safe manner.
++     * <p/>
++     * If the value returned from the specified map is not a Map then
++     * <code>null</code> is returned.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a Map, <code>null</code> if null map input
++     */
++    public static <K,A,B> Map<A, B> getMap(final Map<K, Map<A, B>> map, final K key) {
++        if (map != null) {
++            Map<A, B> answer = map.get(key);
++            if (answer != null) {
++                return answer;
++            }
++        }
++        return null;
++    }
++
++    // Type safe getters with default values
++    //-------------------------------------------------------------------------
++    /**
++     * Looks up the given key in the given map, converting null into the
++     * given default value.
++     *
++     * @param map          the map whose value to look up
++     * @param key          the key of the value to look up in that map
++     * @param defaultValue what to return if the value is null
++     * @return the value in the map, or defaultValue if the original value
++     *         is null or the map is null
++     */
++    public static <K,V> V getObject(Map<K, V> map, K key, V defaultValue) {
++        if (map != null) {
++            V answer = map.get(key);
++            if (answer != null) {
++                return answer;
++            }
++        }
++        return defaultValue;
++    }
++
++    /**
++     * Looks up the given key in the given map, converting the result into
++     * a string, using the default value if the the conversion fails.
++     *
++     * @param map          the map whose value to look up
++     * @param key          the key of the value to look up in that map
++     * @param defaultValue what to return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the map as a string, or defaultValue if the
++     *         original value is null, the map is null or the string conversion
++     *         fails
++     */
++    public static String getString(Map map, Object key, String defaultValue) {
++        String answer = getString(map, key);
++        if (answer == null) {
++            answer = defaultValue;
++        }
++        return answer;
++    }
++
++    /**
++     * Looks up the given key in the given map, converting the result into
++     * a boolean, using the default value if the the conversion fails.
++     *
++     * @param map          the map whose value to look up
++     * @param key          the key of the value to look up in that map
++     * @param defaultValue what to return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the map as a boolean, or defaultValue if the
++     *         original value is null, the map is null or the boolean conversion
++     *         fails
++     */
++    public static Boolean getBoolean(Map map, Object key, Boolean defaultValue) {
++        Boolean answer = getBoolean(map, key);
++        if (answer == null) {
++            answer = defaultValue;
++        }
++        return answer;
++    }
++
++    /**
++     * Looks up the given key in the given map, converting the result into
++     * a number, using the default value if the the conversion fails.
++     *
++     * @param map          the map whose value to look up
++     * @param key          the key of the value to look up in that map
++     * @param defaultValue what to return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the map as a number, or defaultValue if the
++     *         original value is null, the map is null or the number conversion
++     *         fails
++     */
++    public static Number getNumber(Map map, Object key, Number defaultValue) {
++        Number answer = getNumber(map, key);
++        if (answer == null) {
++            answer = defaultValue;
++        }
++        return answer;
++    }
++
++    /**
++     * Looks up the given key in the given map, converting the result into
++     * a byte, using the default value if the the conversion fails.
++     *
++     * @param map          the map whose value to look up
++     * @param key          the key of the value to look up in that map
++     * @param defaultValue what to return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the map as a number, or defaultValue if the
++     *         original value is null, the map is null or the number conversion
++     *         fails
++     */
++    public static Byte getByte(Map map, Object key, Byte defaultValue) {
++        Byte answer = getByte(map, key);
++        if (answer == null) {
++            answer = defaultValue;
++        }
++        return answer;
++    }
++
++    /**
++     * Looks up the given key in the given map, converting the result into
++     * a short, using the default value if the the conversion fails.
++     *
++     * @param map          the map whose value to look up
++     * @param key          the key of the value to look up in that map
++     * @param defaultValue what to return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the map as a number, or defaultValue if the
++     *         original value is null, the map is null or the number conversion
++     *         fails
++     */
++    public static Short getShort(Map map, Object key, Short defaultValue) {
++        Short answer = getShort(map, key);
++        if (answer == null) {
++            answer = defaultValue;
++        }
++        return answer;
++    }
++
++    /**
++     * Looks up the given key in the given map, converting the result into
++     * an integer, using the default value if the the conversion fails.
++     *
++     * @param map          the map whose value to look up
++     * @param key          the key of the value to look up in that map
++     * @param defaultValue what to return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the map as a number, or defaultValue if the
++     *         original value is null, the map is null or the number conversion
++     *         fails
++     */
++    public static Integer getInteger(Map map, Object key, Integer defaultValue) {
++        Integer answer = getInteger(map, key);
++        if (answer == null) {
++            answer = defaultValue;
++        }
++        return answer;
++    }
++
++    /**
++     * Looks up the given key in the given map, converting the result into
++     * a long, using the default value if the the conversion fails.
++     *
++     * @param map          the map whose value to look up
++     * @param key          the key of the value to look up in that map
++     * @param defaultValue what to return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the map as a number, or defaultValue if the
++     *         original value is null, the map is null or the number conversion
++     *         fails
++     */
++    public static Long getLong(Map map, Object key, Long defaultValue) {
++        Long answer = getLong(map, key);
++        if (answer == null) {
++            answer = defaultValue;
++        }
++        return answer;
++    }
++
++    /**
++     * Looks up the given key in the given map, converting the result into
++     * a float, using the default value if the the conversion fails.
++     *
++     * @param map          the map whose value to look up
++     * @param key          the key of the value to look up in that map
++     * @param defaultValue what to return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the map as a number, or defaultValue if the
++     *         original value is null, the map is null or the number conversion
++     *         fails
++     */
++    public static Float getFloat(Map map, Object key, Float defaultValue) {
++        Float answer = getFloat(map, key);
++        if (answer == null) {
++            answer = defaultValue;
++        }
++        return answer;
++    }
++
++    /**
++     * Looks up the given key in the given map, converting the result into
++     * a double, using the default value if the the conversion fails.
++     *
++     * @param map          the map whose value to look up
++     * @param key          the key of the value to look up in that map
++     * @param defaultValue what to return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the map as a number, or defaultValue if the
++     *         original value is null, the map is null or the number conversion
++     *         fails
++     */
++    public static Double getDouble(Map map, Object key, Double defaultValue) {
++        Double answer = getDouble(map, key);
++        if (answer == null) {
++            answer = defaultValue;
++        }
++        return answer;
++    }
++
++    /**
++     * Looks up the given key in the given map, converting the result into
++     * a map, using the default value if the the conversion fails.
++     *
++     * @param map          the map whose value to look up
++     * @param key          the key of the value to look up in that map
++     * @param defaultValue what to return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the map as a number, or defaultValue if the
++     *         original value is null, the map is null or the map conversion
++     *         fails
++     */
++    public static <K,A,B> Map<A, B> getMap(Map<K, Map<A, B>> map, K key, Map<A, B> defaultValue) {
++        Map<A, B> answer = getMap(map, key);
++        if (answer == null) {
++            answer = defaultValue;
++        }
++        return answer;
++    }
++    
++
++    // Type safe primitive getters
++    //-------------------------------------------------------------------------
++    /**
++     * Gets a boolean from a Map in a null-safe manner.
++     * <p/>
++     * If the value is a <code>Boolean</code> its value is returned.
++     * If the value is a <code>String</code> and it equals 'true' ignoring case
++     * then <code>true</code> is returned, otherwise <code>false</code>.
++     * If the value is a <code>Number</code> an integer zero value returns
++     * <code>false</code> and non-zero returns <code>true</code>.
++     * Otherwise, <code>false</code> is returned.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a Boolean, <code>false</code> if null map input
++     */
++    public static boolean getBooleanValue(final Map map, final Object key) {
++        Boolean booleanObject = getBoolean(map, key);
++        if (booleanObject == null) {
++            return false;
++        }
++        return booleanObject.booleanValue();
++    }
++
++    /**
++     * Gets a byte from a Map in a null-safe manner.
++     * <p/>
++     * The byte is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a byte, <code>0</code> if null map input
++     */
++    public static byte getByteValue(final Map map, final Object key) {
++        Byte byteObject = getByte(map, key);
++        if (byteObject == null) {
++            return 0;
++        }
++        return byteObject.byteValue();
++    }
++
++    /**
++     * Gets a short from a Map in a null-safe manner.
++     * <p/>
++     * The short is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a short, <code>0</code> if null map input
++     */
++    public static short getShortValue(final Map map, final Object key) {
++        Short shortObject = getShort(map, key);
++        if (shortObject == null) {
++            return 0;
++        }
++        return shortObject.shortValue();
++    }
++
++    /**
++     * Gets an int from a Map in a null-safe manner.
++     * <p/>
++     * The int is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as an int, <code>0</code> if null map input
++     */
++    public static int getIntValue(final Map map, final Object key) {
++        Integer integerObject = getInteger(map, key);
++        if (integerObject == null) {
++            return 0;
++        }
++        return integerObject.intValue();
++    }
++
++    /**
++     * Gets a long from a Map in a null-safe manner.
++     * <p/>
++     * The long is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a long, <code>0L</code> if null map input
++     */
++    public static long getLongValue(final Map map, final Object key) {
++        Long longObject = getLong(map, key);
++        if (longObject == null) {
++            return 0L;
++        }
++        return longObject.longValue();
++    }
++
++    /**
++     * Gets a float from a Map in a null-safe manner.
++     * <p/>
++     * The float is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a float, <code>0.0F</code> if null map input
++     */
++    public static float getFloatValue(final Map map, final Object key) {
++        Float floatObject = getFloat(map, key);
++        if (floatObject == null) {
++            return 0f;
++        }
++        return floatObject.floatValue();
++    }
++
++    /**
++     * Gets a double from a Map in a null-safe manner.
++     * <p/>
++     * The double is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map the map to use
++     * @param key the key to look up
++     * @return the value in the Map as a double, <code>0.0</code> if null map input
++     */
++    public static double getDoubleValue(final Map map, final Object key) {
++        Double doubleObject = getDouble(map, key);
++        if (doubleObject == null) {
++            return 0d;
++        }
++        return doubleObject.doubleValue();
++    }
++
++    // Type safe primitive getters with default values
++    //-------------------------------------------------------------------------
++    /**
++     * Gets a boolean from a Map in a null-safe manner,
++     * using the default value if the the conversion fails.
++     * <p/>
++     * If the value is a <code>Boolean</code> its value is returned.
++     * If the value is a <code>String</code> and it equals 'true' ignoring case
++     * then <code>true</code> is returned, otherwise <code>false</code>.
++     * If the value is a <code>Number</code> an integer zero value returns
++     * <code>false</code> and non-zero returns <code>true</code>.
++     * Otherwise, <code>defaultValue</code> is returned.
++     *
++     * @param map          the map to use
++     * @param key          the key to look up
++     * @param defaultValue return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the Map as a Boolean, <code>defaultValue</code> if null map input
++     */
++    public static boolean getBooleanValue(final Map map, final Object key, boolean defaultValue) {
++        Boolean booleanObject = getBoolean(map, key);
++        if (booleanObject == null) {
++            return defaultValue;
++        }
++        return booleanObject.booleanValue();
++    }
++
++    /**
++     * Gets a byte from a Map in a null-safe manner,
++     * using the default value if the the conversion fails.
++     * <p/>
++     * The byte is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map          the map to use
++     * @param key          the key to look up
++     * @param defaultValue return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the Map as a byte, <code>defaultValue</code> if null map input
++     */
++    public static byte getByteValue(final Map map, final Object key, byte defaultValue) {
++        Byte byteObject = getByte(map, key);
++        if (byteObject == null) {
++            return defaultValue;
++        }
++        return byteObject.byteValue();
++    }
++
++    /**
++     * Gets a short from a Map in a null-safe manner,
++     * using the default value if the the conversion fails.
++     * <p/>
++     * The short is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map          the map to use
++     * @param key          the key to look up
++     * @param defaultValue return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the Map as a short, <code>defaultValue</code> if null map input
++     */
++    public static short getShortValue(final Map map, final Object key, short defaultValue) {
++        Short shortObject = getShort(map, key);
++        if (shortObject == null) {
++            return defaultValue;
++        }
++        return shortObject.shortValue();
++    }
++
++    /**
++     * Gets an int from a Map in a null-safe manner,
++     * using the default value if the the conversion fails.
++     * <p/>
++     * The int is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map          the map to use
++     * @param key          the key to look up
++     * @param defaultValue return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the Map as an int, <code>defaultValue</code> if null map input
++     */
++    public static int getIntValue(final Map map, final Object key, int defaultValue) {
++        Integer integerObject = getInteger(map, key);
++        if (integerObject == null) {
++            return defaultValue;
++        }
++        return integerObject.intValue();
++    }
++
++    /**
++     * Gets a long from a Map in a null-safe manner,
++     * using the default value if the the conversion fails.
++     * <p/>
++     * The long is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map          the map to use
++     * @param key          the key to look up
++     * @param defaultValue return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the Map as a long, <code>defaultValue</code> if null map input
++     */
++    public static long getLongValue(final Map map, final Object key, long defaultValue) {
++        Long longObject = getLong(map, key);
++        if (longObject == null) {
++            return defaultValue;
++        }
++        return longObject.longValue();
++    }
++
++    /**
++     * Gets a float from a Map in a null-safe manner,
++     * using the default value if the the conversion fails.
++     * <p/>
++     * The float is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map          the map to use
++     * @param key          the key to look up
++     * @param defaultValue return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the Map as a float, <code>defaultValue</code> if null map input
++     */
++    public static float getFloatValue(final Map map, final Object key, float defaultValue) {
++        Float floatObject = getFloat(map, key);
++        if (floatObject == null) {
++            return defaultValue;
++        }
++        return floatObject.floatValue();
++    }
++
++    /**
++     * Gets a double from a Map in a null-safe manner,
++     * using the default value if the the conversion fails.
++     * <p/>
++     * The double is obtained from the results of {@link #getNumber(Map,Object)}.
++     *
++     * @param map          the map to use
++     * @param key          the key to look up
++     * @param defaultValue return if the value is null or if the
++     *                     conversion fails
++     * @return the value in the Map as a double, <code>defaultValue</code> if null map input
++     */
++    public static double getDoubleValue(final Map map, final Object key, double defaultValue) {
++        Double doubleObject = getDouble(map, key);
++        if (doubleObject == null) {
++            return defaultValue;
++        }
++        return doubleObject.doubleValue();
++    }
++
++    // Conversion methods
++    //-------------------------------------------------------------------------
++    /**
++     * Gets a new Properties object initialised with the values from a Map.
++     * A null input will return an empty properties object.
++     *
++     * @param map the map to convert to a Properties object, may not be null
++     * @return the properties object
++     */
++    public static Properties toProperties(final Map map) {
++        Properties answer = new Properties();
++        if (map != null) {
++            for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
++                Map.Entry entry = (Map.Entry) iter.next();
++                Object key = entry.getKey();
++                Object value = entry.getValue();
++                answer.put(key, value);
++            }
++        }
++        return answer;
++    }
++
++    /**
++     * Creates a new HashMap using data copied from a ResourceBundle.
++     *
++     * @param resourceBundle the resource bundle to convert, may not be null
++     * @return the hashmap containing the data
++     * @throws NullPointerException if the bundle is null
++     */
++    public static Map<String, Object> toMap(final ResourceBundle resourceBundle) {
++        Enumeration<String> enumeration = resourceBundle.getKeys();
++        Map<String, Object> map = new HashMap<String, Object>();
++
++        while (enumeration.hasMoreElements()) {
++            String key = enumeration.nextElement();
++            Object value = resourceBundle.getObject(key);
++            map.put(key, value);
++        }
++
++        return map;
++    }
++ 
++    // Printing methods
++    //-------------------------------------------------------------------------
++    /**
++     * Prints the given map with nice line breaks.
++     * <p/>
++     * This method prints a nicely formatted String describing the Map.
++     * Each map entry will be printed with key and value.
++     * When the value is a Map, recursive behaviour occurs.
++     * <p/>
++     * This method is NOT thread-safe in any special way. You must manually
++     * synchronize on either this class or the stream as required.
++     *
++     * @param out   the stream to print to, must not be null
++     * @param label The label to be used, may be <code>null</code>.
++     *              If <code>null</code>, the label is not output.
++     *              It typically represents the name of the property in a bean or similar.
++     * @param map   The map to print, may be <code>null</code>.
++     *              If <code>null</code>, the text 'null' is output.
++     * @throws NullPointerException if the stream is <code>null</code>
++     */
++    public static void verbosePrint(final PrintStream out, final Object label, final Map map) {
++
++        verbosePrintInternal(out, label, map, new ArrayStack(), false);
++    }
++
++    /**
++     * Prints the given map with nice line breaks.
++     * <p/>
++     * This method prints a nicely formatted String describing the Map.
++     * Each map entry will be printed with key, value and value classname.
++     * When the value is a Map, recursive behaviour occurs.
++     * <p/>
++     * This method is NOT thread-safe in any special way. You must manually
++     * synchronize on either this class or the stream as required.
++     *
++     * @param out   the stream to print to, must not be null
++     * @param label The label to be used, may be <code>null</code>.
++     *              If <code>null</code>, the label is not output.
++     *              It typically represents the name of the property in a bean or similar.
++     * @param map   The map to print, may be <code>null</code>.
++     *              If <code>null</code>, the text 'null' is output.
++     * @throws NullPointerException if the stream is <code>null</code>
++     */
++    public static void debugPrint(final PrintStream out, final Object label, final Map map) {
++
++        verbosePrintInternal(out, label, map, new ArrayStack(), true);
++    }
++
++    // Implementation methods
++    //-------------------------------------------------------------------------
++    /**
++     * Logs the given exception to <code>System.out</code>.
++     * <p/>
++     * This method exists as Jakarta Collections does not depend on logging.
++     *
++     * @param ex the exception to log
++     */
++    protected static void logInfo(final Exception ex) {
++        System.out.println("INFO: Exception: " + ex);
++    }
++
++    /**
++     * Implementation providing functionality for {@link #debugPrint} and for
++     * {@link #verbosePrint}.  This prints the given map with nice line breaks.
++     * If the debug flag is true, it additionally prints the type of the object
++     * value.  If the contents of a map include the map itself, then the text
++     * <em>(this Map)</em> is printed out.  If the contents include a
++     * parent container of the map, the the text <em>(ancestor[i] Map)</em> is
++     * printed, where i actually indicates the number of levels which must be
++     * traversed in the sequential list of ancestors (e.g. father, grandfather,
++     * great-grandfather, etc).
++     *
++     * @param out     the stream to print to
++     * @param label   the label to be used, may be <code>null</code>.
++     *                If <code>null</code>, the label is not output.
++     *                It typically represents the name of the property in a bean or similar.
++     * @param map     the map to print, may be <code>null</code>.
++     *                If <code>null</code>, the text 'null' is output
++     * @param lineage a stack consisting of any maps in which the previous
++     *                argument is contained. This is checked to avoid infinite recursion when
++     *                printing the output
++     * @param debug   flag indicating whether type names should be output.
++     * @throws NullPointerException if the stream is <code>null</code>
++     */
++    private static void verbosePrintInternal(final PrintStream out, final Object label, final Map map, final ArrayStack lineage, final boolean debug) {
++
++        printIndent(out, lineage.size());
++
++        if (map == null) {
++            if (label != null) {
++                out.print(label);
++                out.print(" = ");
++            }
++            out.println("null");
++            return;
++        }
++        if (label != null) {
++            out.print(label);
++            out.println(" = ");
++        }
++
++        printIndent(out, lineage.size());
++        out.println("{");
++
++        lineage.push(map);
++
++        for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
++            Map.Entry entry = (Map.Entry) it.next();
++            Object childKey = entry.getKey();
++            Object childValue = entry.getValue();
++            if (childValue instanceof Map && !lineage.contains(childValue)) {
++                verbosePrintInternal(out, (childKey == null ? "null" : childKey), (Map) childValue, lineage, debug);
++            } else {
++                printIndent(out, lineage.size());
++                out.print(childKey);
++                out.print(" = ");
++
++                final int lineageIndex = lineage.indexOf(childValue);
++                if (lineageIndex == -1) {
++                    out.print(childValue);
++                } else if (lineage.size() - 1 == lineageIndex) {
++                    out.print("(this Map)");
++                } else {
++                    out.print("(ancestor[" + (lineage.size() - 1 - lineageIndex - 1) + "] Map)");
++                }
++
++                if (debug && childValue != null) {
++                    out.print(' ');
++                    out.println(childValue.getClass().getName());
++                } else {
++                    out.println();
++                }
++            }
++        }
++
++        lineage.pop();
++
++        printIndent(out, lineage.size());
++        out.println(debug ? "} " + map.getClass().getName() : "}");
++    }
++
++    /**
++     * Writes indentation to the given stream.
++     *
++     * @param out the stream to indent
++     */
++    private static void printIndent(final PrintStream out, final int indent) {
++        for (int i = 0; i < indent; i++) {
++            out.print(INDENT_STRING);
++        }
++    }
++    
++    // Misc
++    //-----------------------------------------------------------------------
++    /**
++     * Inverts the supplied map returning a new HashMap such that the keys of
++     * the input are swapped with the values.
++     * <p/>
++     * This operation assumes that the inverse mapping is well defined.
++     * If the input map had multiple entries with the same value mapped to
++     * different keys, the returned map will map one of those keys to the
++     * value, but the exact key which will be mapped is undefined.
++     *
++     * @param map the map to invert, may not be null
++     * @return a new HashMap containing the inverted data
++     * @throws NullPointerException if the map is null
++     */
++    public static <K,V> Map<V, K> invertMap(Map<K, V> map) {
++        Map<V, K> out = new HashMap<V, K>(map.size());
++        for (Iterator<Map.Entry<K, V>> it = map.entrySet().iterator(); it.hasNext();) {
++            Map.Entry<K, V> entry = it.next();
++            out.put(entry.getValue(), entry.getKey());
++        }
++        return out;
++    }
++
++    /**
++     * Nice method for adding data to a map in such a way
++     * as to not get NPE's. The point being that if the
++     * value is null, map.put() will throw an exception.
++     * That blows in the case of this class cause you may want to
++     * essentially treat put("Not Null", null ) == put("Not Null", "")
++     * We will still throw a NPE if the key is null cause that should
++     * never happen.
++     * <p>
++     * Note: this is not a type-safe operation in Java 1.5.
++     *
++     * @param map   the map to add to, may not be null
++     * @param key   the key
++     * @param value the value
++     * @throws NullPointerException if the map is null
++     *
++     */
++    public static void safeAddToMap(Map map, Object key, Object value) throws NullPointerException {
++        if (value == null) {
++            map.put(key, "");
++        } else {
++            map.put(key, value);
++        }
++    }
++
++    // Map decorators
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a synchronized map backed by the given map.
++     * <p/>
++     * You must manually synchronize on the returned buffer's iterator to
++     * avoid non-deterministic behavior:
++     * <p/>
++     * <pre>
++     * Map m = MapUtils.synchronizedMap(myMap);
++     * Set s = m.keySet();  // outside synchronized block
++     * synchronized (m) {  // synchronized on MAP!
++     *     Iterator i = s.iterator();
++     *     while (i.hasNext()) {
++     *         process (i.next());
++     *     }
++     * }
++     * </pre>
++     * <p/>
++     * This method uses the implementation in {@link java.util.Collections Collections}.
++     *
++     * @param map the map to synchronize, must not be null
++     * @return a synchronized map backed by the given map
++     * @throws IllegalArgumentException if the map is null
++     */
++    public static <K,V> Map<K, V> synchronizedMap(Map<K, V> map) {
++        return Collections.synchronizedMap(map);
++    }
++
++    /**
++     * Returns an unmodifiable map backed by the given map.
++     * <p/>
++     * This method uses the implementation in the decorators subpackage.
++     *
++     * @param map the map to make unmodifiable, must not be null
++     * @return an unmodifiable map backed by the given map
++     * @throws IllegalArgumentException if the map is null
++     */
++    public static <K,V> Map<K, V> unmodifiableMap(Map<K, V> map) {
++        return UnmodifiableMap.decorate(map);
++    }
++
++    /**
++     * Returns a predicated (validating) map backed by the given map.
++     * <p/>
++     * Only objects that pass the tests in the given predicates can be added to the map.
++     * Trying to add an invalid object results in an IllegalArgumentException.
++     * Keys must pass the key predicate, values must pass the value predicate.
++     * It is important not to use the original map after invoking this method,
++     * as it is a backdoor for adding invalid objects.
++     *
++     * @param map       the map to predicate, must not be null
++     * @param keyPred   the predicate for keys, null means no check
++     * @param valuePred the predicate for values, null means no check
++     * @return a predicated map backed by the given map
++     * @throws IllegalArgumentException if the Map is null
++     */
++    public static <K,V> Map<K, V> predicatedMap(Map<K, V> map, Predicate<? super K> keyPred, Predicate<? super V> valuePred) {
++        return PredicatedMap.decorate(map, keyPred, valuePred);
++    }
++
++    /**
++     * Returns a typed map backed by the given map.
++     * <p/>
++     * Only keys and values of the specified types can be added to the map.
++     *
++     * @param map       the map to limit to a specific type, must not be null
++     * @param keyType   the type of keys which may be added to the map, must not be null
++     * @param valueType the type of values which may be added to the map, must not be null
++     * @return a typed map backed by the specified map
++     * @throws IllegalArgumentException if the Map or Class is null
++     * @deprecated this is no longer needed with Java generics.
++     */
++    public static Map typedMap(Map map, Class keyType, Class valueType) {
++        return TypedMap.decorate(map, keyType, valueType);
++    }
++
++    /**
++     * Returns a transformed map backed by the given map.
++     * <p/>
++     * Each object is passed through the transformers as it is added to the
++     * Map. It is important not to use the original map after invoking this
++     * method, as it is a backdoor for adding untransformed objects.
++     *
++     * @param map              the map to transform, must not be null
++     * @param keyTransformer   the transformer for the map keys, null means no transformation
++     * @param valueTransformer the transformer for the map values, null means no transformation
++     * @return a transformed map backed by the given map
++     * @throws IllegalArgumentException if the Map is null
++     */
++    public static Map transformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
++        return TransformedMap.decorate(map, keyTransformer, valueTransformer);
++    }
++
++    /**
++     * Returns a fixed-sized map backed by the given map.
++     * Elements may not be added or removed from the returned map, but
++     * existing elements can be changed (for instance, via the
++     * {@link Map#put(Object,Object)} method).
++     *
++     * @param map the map whose size to fix, must not be null
++     * @return a fixed-size map backed by that map
++     * @throws IllegalArgumentException if the Map is null
++     */
++    public static <K,V> Map<K, V> fixedSizeMap(Map<K, V> map) {
++        return FixedSizeMap.decorate(map);
++    }
++
++    /**
++     * Returns a "lazy" map whose values will be created on demand.
++     * <p/>
++     * When the key passed to the returned map's {@link Map#get(Object)}
++     * method is not present in the map, then the factory will be used
++     * to create a new object and that object will become the value
++     * associated with that key.
++     * <p/>
++     * For instance:
++     * <pre>
++     * Factory factory = new Factory() {
++     *     public Object create() {
++     *         return new Date();
++     *     }
++     * }
++     * Map lazyMap = MapUtils.lazyMap(new HashMap(), factory);
++     * Object obj = lazyMap.get("test");
++     * </pre>
++     * <p/>
++     * After the above code is executed, <code>obj</code> will contain
++     * a new <code>Date</code> instance.  Furthermore, that <code>Date</code>
++     * instance is the value for the <code>"test"</code> key in the map.
++     *
++     * @param map     the map to make lazy, must not be null
++     * @param factory the factory for creating new objects, must not be null
++     * @return a lazy map backed by the given map
++     * @throws IllegalArgumentException if the Map or Factory is null
++     */
++    public static <K,V> Map<K, V> lazyMap(Map<K, V> map, Factory<V> factory) {
++        return LazyMap.decorate(map, factory);
++    }
++
++    /**
++     * Returns a map that maintains the order of keys that are added
++     * backed by the given map.
++     * <p/>
++     * If a key is added twice, the order is determined by the first add.
++     * The order is observed through the keySet, values and entrySet.
++     *
++     * @param map the map to order, must not be null
++     * @return an ordered map backed by the given map
++     * @throws IllegalArgumentException if the Map is null
++     */
++    public static <K,V> Map<K, V> orderedMap(Map<K, V> map) {
++        return ListOrderedMap.decorate(map);
++    }
++    
++    // SortedMap decorators
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a synchronized sorted map backed by the given sorted map.
++     * <p/>
++     * You must manually synchronize on the returned buffer's iterator to
++     * avoid non-deterministic behavior:
++     * <p/>
++     * <pre>
++     * Map m = MapUtils.synchronizedSortedMap(myMap);
++     * Set s = m.keySet();  // outside synchronized block
++     * synchronized (m) {  // synchronized on MAP!
++     *     Iterator i = s.iterator();
++     *     while (i.hasNext()) {
++     *         process (i.next());
++     *     }
++     * }
++     * </pre>
++     * <p/>
++     * This method uses the implementation in {@link java.util.Collections Collections}.
++     *
++     * @param map the map to synchronize, must not be null
++     * @return a synchronized map backed by the given map
++     * @throws IllegalArgumentException if the map is null
++     */
++    public static <K,V> Map<K, V> synchronizedSortedMap(SortedMap<K, V> map) {
++        return Collections.synchronizedSortedMap(map);
++    }
++
++    /**
++     * Returns an unmodifiable sorted map backed by the given sorted map.
++     * <p/>
++     * This method uses the implementation in the decorators subpackage.
++     *
++     * @param map the sorted map to make unmodifiable, must not be null
++     * @return an unmodifiable map backed by the given map
++     * @throws IllegalArgumentException if the map is null
++     */
++    public static <K,V> Map<K, V> unmodifiableSortedMap(SortedMap<K, V> map) {
++        return UnmodifiableSortedMap.decorate(map);
++    }
++
++    /**
++     * Returns a predicated (validating) sorted map backed by the given map.
++     * <p/>
++     * Only objects that pass the tests in the given predicates can be added to the map.
++     * Trying to add an invalid object results in an IllegalArgumentException.
++     * Keys must pass the key predicate, values must pass the value predicate.
++     * It is important not to use the original map after invoking this method,
++     * as it is a backdoor for adding invalid objects.
++     *
++     * @param map       the map to predicate, must not be null
++     * @param keyPred   the predicate for keys, null means no check
++     * @param valuePred the predicate for values, null means no check
++     * @return a predicated map backed by the given map
++     * @throws IllegalArgumentException if the SortedMap is null
++     */
++    public static <K,V> SortedMap<K, V> predicatedSortedMap(SortedMap<K, V> map, Predicate<? super K> keyPred, Predicate<? super V> valuePred) {
++        return PredicatedSortedMap.decorate(map, keyPred, valuePred);
++    }
++
++    /**
++     * Returns a typed sorted map backed by the given map.
++     * <p/>
++     * Only keys and values of the specified types can be added to the map.
++     *
++     * @param map       the map to limit to a specific type, must not be null
++     * @param keyType   the type of keys which may be added to the map, must not be null
++     * @param valueType the type of values which may be added to the map, must not be null
++     * @return a typed map backed by the specified map
++     * @deprecated no longer needed with Java generics.
++     */
++    public static SortedMap typedSortedMap(SortedMap map, Class keyType, Class valueType) {
++        return TypedSortedMap.decorate(map, keyType, valueType);
++    }
++
++    /**
++     * Returns a transformed sorted map backed by the given map.
++     * <p/>
++     * Each object is passed through the transformers as it is added to the
++     * Map. It is important not to use the original map after invoking this
++     * method, as it is a backdoor for adding untransformed objects.
++     *
++     * @param map              the map to transform, must not be null
++     * @param keyTransformer   the transformer for the map keys, null means no transformation
++     * @param valueTransformer the transformer for the map values, null means no transformation
++     * @return a transformed map backed by the given map
++     * @throws IllegalArgumentException if the SortedMap is null
++     */
++    public static SortedMap transformedSortedMap(SortedMap map, Transformer keyTransformer, Transformer valueTransformer) {
++        return TransformedSortedMap.decorate(map, keyTransformer, valueTransformer);
++    }
++
++    /**
++     * Returns a fixed-sized sorted map backed by the given sorted map.
++     * Elements may not be added or removed from the returned map, but
++     * existing elements can be changed (for instance, via the
++     * {@link Map#put(Object,Object)} method).
++     *
++     * @param map the map whose size to fix, must not be null
++     * @return a fixed-size map backed by that map
++     * @throws IllegalArgumentException if the SortedMap is null
++     */
++    public static <K,V> SortedMap<K, V> fixedSizeSortedMap(SortedMap<K, V> map) {
++        return FixedSizeSortedMap.decorate(map);
++    }
++
++    /**
++     * Returns a "lazy" sorted map whose values will be created on demand.
++     * <p/>
++     * When the key passed to the returned map's {@link Map#get(Object)}
++     * method is not present in the map, then the factory will be used
++     * to create a new object and that object will become the value
++     * associated with that key.
++     * <p/>
++     * For instance:
++     * <p/>
++     * <pre>
++     * Factory factory = new Factory() {
++     *     public Object create() {
++     *         return new Date();
++     *     }
++     * }
++     * SortedMap lazy = MapUtils.lazySortedMap(new TreeMap(), factory);
++     * Object obj = lazy.get("test");
++     * </pre>
++     * <p/>
++     * After the above code is executed, <code>obj</code> will contain
++     * a new <code>Date</code> instance.  Furthermore, that <code>Date</code>
++     * instance is the value for the <code>"test"</code> key.
++     *
++     * @param map     the map to make lazy, must not be null
++     * @param factory the factory for creating new objects, must not be null
++     * @return a lazy map backed by the given map
++     * @throws IllegalArgumentException if the SortedMap or Factory is null
++     */
++    public static <K,V> SortedMap<K, V> lazySortedMap(SortedMap<K, V> map, Factory<V> factory) {
++        return LazySortedMap.decorate(map, factory);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/MultiMap.java
+@@ -0,0 +1,337 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.*;
++
++/**
++ * Defines a map that holds a collection of values against each key.
++ * <p/>
++ * A <code>MultiMap</code> is a Map with slightly different semantics.
++ * Putting a value into the map will add the value to a Collection at that key.
++ * Getting a value will return a Collection, holding all the values put to that key.
++ * <p/>
++ * For example:
++ * <pre>
++ * Number key = new Integer(5);
++ * MultiMap<Number,String> mhm = new MultiHashMap<Number,String>();
++ * mhm.put(key, "A");
++ * mhm.put(key, "B");
++ * mhm.put(key, "C");
++ * Collection<String> coll = mhm.get(key);</pre>
++ * <p/>
++ * <code>coll</code> will be a collection containing "A", "B", "C".
++ * <p/>
++ * NOTE: Note: this new, generics-friendly version of the MultiMap interface does
++ * NOT extend java.util.Map! This is because MultiMap breaks the Map contract in
++ * too many ways to allow generics support. However, you can get a live java.util.Map
++ * for a MultiMap with the method {@link #map()}.
++ *
++ * @author Christopher Berry
++ * @author James Strachan
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.0
++ */
++public interface MultiMap <K,V> {
++
++    /**
++     * Removes a specific value from map.
++     * <p/>
++     * The item is removed from the collection mapped to the specified key.
++     * Other values attached to that key are unaffected.
++     * <p/>
++     * If the last value for a key is removed, implementations typically
++     * return <code>null</code> from a subsequant <code>get(Object)</code>, however
++     * they may choose to return an empty collection.
++     *
++     * @param key  the key to remove from
++     * @param item the item to remove
++     * @return the value removed (which was passed in), null if nothing removed
++     * @throws UnsupportedOperationException if the map is unmodifiable
++     * @throws ClassCastException            if the key or value is of an invalid type
++     * @throws NullPointerException          if the key or value is null and null is invalid
++     */
++    public V remove(Object key, Object item);
++
++    /**
++     * Gets the number of values in this map for the given key.
++     * <p/>
++     * Implementations return the count of keys in the map, or 0 if there are no values for the given key.
++     *
++     * @return the number of values in this map for the given key.
++     */
++    int size(Object key);
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the number of keys in this map.
++     * <p/>
++     * Implementations return the count of keys in the map.
++     *
++     * @return the number of key-collection mappings in this map
++     */
++    int size();
++
++    /**
++     * Gets the collection of values associated with the specified key.
++     * <p/>
++     * The returned value will implement <code>Collection</code>. Implementations
++     * are free to declare that they return <code>Collection</code> subclasses
++     * such as <code>List</code> or <code>Set</code>.
++     * <p/>
++     * Implementations return <code>null</code> if no values have
++     * been mapped to the key.
++     * <p/>
++     * Implementations may choose to return a clone of the internal collection.
++     *
++     * @param key the key to retrieve
++     * @return the <code>Collection</code> of values, implementations should
++     *         return <code>null</code> for no mapping, but may return an empty collection
++     * @throws ClassCastException   if the key is of an invalid type
++     * @throws NullPointerException if the key is null and null keys are invalid
++     */
++    Collection<V> get(Object key);
++
++    /**
++     * Checks whether the map contains the value specified.
++     * <p/>
++     * Implementations check all collections15 against all keys for the value.
++     *
++     * @param value the value to search for
++     * @return true if the map contains the value
++     * @throws ClassCastException   if the value is of an invalid type
++     * @throws NullPointerException if the value is null and null value are invalid
++     */
++    boolean containsValue(Object value);
++
++    /**
++     * Checks whether the map contains the value specified, at the key specified.
++     *
++     * @param value the value to search for
++     * @param key the key against which to search for the value
++     * @return true if the map contains the value
++     * @throws ClassCastException   if the value is of an invalid type
++     * @throws NullPointerException if the value is null and null value are invalid
++     */
++    boolean containsValue(Object key, Object value);
++
++    /**
++     * Adds the value to the collection associated with the specified key.
++     * <p/>
++     * Unlike a normal <code>Map</code> the previous value is not replaced.
++     * Instead the new value is added to the collection stored against the key.
++     * The collection may be a <code>List</code>, <code>Set</code> or other
++     * collection dependent on implementation.
++     *
++     * @param key   the key to store against
++     * @param value the value to add to the collection at the key
++     * @return typically the value added if the map changed and null if the map did not change
++     * @throws UnsupportedOperationException if the map is unmodifiable
++     * @throws ClassCastException            if the key or value is of an invalid type
++     * @throws NullPointerException          if the key or value is null and null is invalid
++     * @throws IllegalArgumentException      if the key or value is invalid
++     */
++    V put(K key, V value);
++
++    /**
++     * Removes all values associated with the specified key.
++     * <p/>
++     * Implementations typically return <code>null</code> from a subsequent
++     * <code>get(Object)</code>, however they may choose to return an empty collection.
++     *
++     * @param key the key to remove values from
++     * @return the <code>Collection</code> of values removed, implementations should
++     *         return <code>null</code> for no mapping found, but may return an empty collection
++     * @throws UnsupportedOperationException if the map is unmodifiable
++     * @throws ClassCastException            if the key is of an invalid type
++     * @throws NullPointerException          if the key is null and null keys are invalid
++     */
++    Collection<V> remove(Object key);
++
++    /**
++     * Gets a collection containing all the values in the map.
++     * <p/>
++     * Inplementations return a collection containing the combination
++     * of values from all keys.
++     *
++     * @return a collection view of the values contained in this map
++     */
++    Collection<V> values();
++
++    /**
++     * Returns <tt>true</tt> if this map contains no key-value mappings.
++     *
++     * @return <tt>true</tt> if this map contains no key-value mappings.
++     */
++    boolean isEmpty();
++
++    /**
++     * Returns <tt>true</tt> if this map contains a mapping for the specified
++     * key.  More formally, returns <tt>true</tt> if and only if
++     * this map contains a mapping for a key <tt>k</tt> such that
++     * <tt>(key==null ? k==null : key.equals(k))</tt>.  (There can be
++     * at most one such mapping.)
++     *
++     * @param key key whose presence in this map is to be tested.
++     * @return <tt>true</tt> if this map contains a mapping for the specified
++     *         key.
++     * @throws ClassCastException   if the key is of an inappropriate type for
++     *                              this map (optional).
++     * @throws NullPointerException if the key is <tt>null</tt> and this map
++     *                              does not permit <tt>null</tt> keys (optional).
++     */
++    boolean containsKey(Object key);
++
++    // Modification Operations
++
++    // Bulk Operations
++
++    /**
++     * Copies all of the mappings from the specified map to this map
++     * (optional operation).  The effect of this call is equivalent to that
++     * of calling {@link #put(Object,Object) put(k, v)} on this map once
++     * for each mapping from key <tt>k</tt> to value <tt>v</tt> in the
++     * specified map.  The behavior of this operation is unspecified if the
++     * specified map is modified while the operation is in progress.
++     *
++     * @param t Mappings to be stored in this map.
++     * @throws UnsupportedOperationException if the <tt>putAll</tt> method is
++     *                                       not supported by this map.
++     * @throws ClassCastException            if the class of a key or value in the
++     *                                       specified map prevents it from being stored in this map.
++     * @throws IllegalArgumentException      some aspect of a key or value in the
++     *                                       specified map prevents it from being stored in this map.
++     * @throws NullPointerException          if the specified map is <tt>null</tt>, or if
++     *                                       this map does not permit <tt>null</tt> keys or values, and the
++     *                                       specified map contains <tt>null</tt> keys or values.
++     */
++    void putAll(Map<? extends K, ? extends V> t);
++
++    /**
++     * Copies all of the mappings from the specified multimap to this multimap
++     * (optional operation).  The effect of this call is equivalent to that
++     * of calling {@link #put(Object,Object) put(k, v)} on this map once
++     * for each mapping from key to collections15 of values in the
++     * specified multimap.  The behavior of this operation is unspecified if the
++     * specified multimap is modified while the operation is in progress.
++     *
++     * @param t Mappings to be stored in this map.
++     * @throws UnsupportedOperationException if the <tt>putAll</tt> method is
++     *                                       not supported by this map.
++     * @throws ClassCastException            if the class of a key or value in the
++     *                                       specified map prevents it from being stored in this map.
++     * @throws IllegalArgumentException      some aspect of a key or value in the
++     *                                       specified map prevents it from being stored in this map.
++     * @throws NullPointerException          if the specified map is <tt>null</tt>, or if
++     *                                       this map does not permit <tt>null</tt> keys or values, and the
++     *                                       specified map contains <tt>null</tt> keys or values.
++     */
++    void putAll(MultiMap<? extends K, ? extends V> t);
++
++    /**
++     * Copies all of the values in the given collection in to the multimap against the given key.
++     * @param key the key against which to store the values.
++     * @param values the collection of values to map to the key.
++     */
++    boolean putAll(K key, Collection<? extends V> values);
++
++    Iterator<V> iterator(Object key);
++
++    /**
++     * Removes all mappings from this map (optional operation).
++     *
++     * @throws UnsupportedOperationException clear is not supported by this
++     *                                       map.
++     */
++    void clear();
++
++
++    // Views
++
++    /**
++     * Returns a set view of the keys contained in this map.  The set is
++     * backed by the map, so changes to the map are reflected in the set, and
++     * vice-versa.  If the map is modified while an iteration over the set is
++     * in progress (except through the iterator's own <tt>remove</tt>
++     * operation), the results of the iteration are undefined.  The set
++     * supports element removal, which removes the corresponding mapping from
++     * the map, via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
++     * <tt>removeAll</tt> <tt>retainAll</tt>, and <tt>clear</tt> operations.
++     * It does not support the add or <tt>addAll</tt> operations.
++     *
++     * @return a set view of the keys contained in this map.
++     */
++    Set<K> keySet();
++
++    /**
++     * Returns a set view of the mappings contained in this map.  Each element
++     * in the returned set is a {@link Map.Entry}.  The set is backed by the
++     * map, so changes to the map are reflected in the set, and vice-versa.
++     * If the map is modified while an iteration over the set is in progress
++     * (except through the iterator's own <tt>remove</tt> operation, or through
++     * the <tt>setValue</tt> operation on a map entry returned by the iterator)
++     * the results of the iteration are undefined.  The set supports element
++     * removal, which removes the corresponding mapping from the map, via the
++     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, <tt>removeAll</tt>,
++     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not support
++     * the <tt>add</tt> or <tt>addAll</tt> operations.
++     *
++     * @return a set view of the mappings contained in this map.
++     */
++    Set<Map.Entry<K, Collection<V>>> entrySet();
++
++    /**
++     * Returns a java.util.Map<K,Collection<V>> for this MultiMap.
++     *
++     * @return the underlying java.util.Map for this MultiMap.
++     */
++    Map<K,Collection<V>> map();
++
++    // Comparison and hashing
++
++    /**
++     * Compares the specified object with this map for equality.  Returns
++     * <tt>true</tt> if the given object is also a map and the two Maps
++     * represent the same mappings.  More formally, two maps <tt>t1</tt> and
++     * <tt>t2</tt> represent the same mappings if
++     * <tt>t1.entrySet().equals(t2.entrySet())</tt>.  This ensures that the
++     * <tt>equals</tt> method works properly across different implementations
++     * of the <tt>Map</tt> interface.
++     *
++     * @param o object to be compared for equality with this map.
++     * @return <tt>true</tt> if the specified object is equal to this map.
++     */
++    boolean equals(Object o);
++
++    /**
++     * Returns the hash code value for this map.  The hash code of a map
++     * is defined to be the sum of the hashCodes of each entry in the map's
++     * entrySet view.  This ensures that <tt>t1.equals(t2)</tt> implies
++     * that <tt>t1.hashCode()==t2.hashCode()</tt> for any two maps
++     * <tt>t1</tt> and <tt>t2</tt>, as required by the general
++     * contract of Object.hashCode.
++     *
++     * @return the hash code value for this map.
++     * @see Map.Entry#hashCode()
++     * @see Object#hashCode()
++     * @see Object#equals(Object)
++     * @see #equals(Object)
++     */
++    int hashCode();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/OrderedBidiMap.java
+@@ -0,0 +1,63 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++/**
++ * Defines a map that allows bidirectional lookup between key and values
++ * and retains and provides access to an ordering.
++ * <p/>
++ * Implementations should allow a value to be looked up from a key and
++ * a key to be looked up from a value with equal performance.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface OrderedBidiMap <K,V> extends BidiMap<K, V>, OrderedMap<K, V> {
++
++    /**
++     * Gets a view of this map where the keys and values are reversed.
++     * <p/>
++     * Changes to one map will be visible in the other and vice versa.
++     * This enables both directions of the map to be accessed equally.
++     * <p/>
++     * Implementations should seek to avoid creating a new object every time this
++     * method is called. See <code>AbstractMap.values()</code> etc. Calling this
++     * method on the inverse map should return the original.
++     * <p/>
++     * Implementations must return an <code>OrderedBidiMap</code> instance,
++     * usually by forwarding to <code>inverseOrderedBidiMap()</code>.
++     *
++     * @return an inverted bidirectional map
++     */
++    public BidiMap<V, K> inverseBidiMap();
++
++    /**
++     * Gets a view of this map where the keys and values are reversed.
++     * <p/>
++     * Changes to one map will be visible in the other and vice versa.
++     * This enables both directions of the map to be accessed equally.
++     * <p/>
++     * Implementations should seek to avoid creating a new object every time this
++     * method is called. See <code>AbstractMap.values()</code> etc. Calling this
++     * method on the inverse map should return the original.
++     *
++     * @return an inverted bidirectional map
++     */
++    public OrderedBidiMap<V, K> inverseOrderedBidiMap();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/OrderedIterator.java
+@@ -0,0 +1,48 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.Iterator;
++
++/**
++ * Defines an iterator that operates over a ordered collections15.
++ * <p/>
++ * This iterator allows both forward and reverse iteration through the collection.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface OrderedIterator <E> extends Iterator<E> {
++
++    /**
++     * Checks to see if there is a previous entry that can be iterated to.
++     *
++     * @return <code>true</code> if the iterator has a previous element
++     */
++    boolean hasPrevious();
++
++    /**
++     * Gets the previous element from the collection.
++     *
++     * @return the previous key in the iteration
++     * @throws java.util.NoSuchElementException
++     *          if the iteration is finished
++     */
++    E previous();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/OrderedMap.java
+@@ -0,0 +1,83 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++/**
++ * Defines a map that maintains order and allows both forward and backward
++ * iteration through that order.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface OrderedMap <K,V> extends IterableMap<K, V> {
++
++    /**
++     * Obtains an <code>OrderedMapIterator</code> over the map.
++     * <p/>
++     * A ordered map iterator is an efficient way of iterating over maps
++     * in both directions.
++     * <pre>
++     * BidiMap map = new TreeBidiMap();
++     * MapIterator it = map.mapIterator();
++     * while (it.hasNext()) {
++     *   Object key = it.next();
++     *   Object value = it.getValue();
++     *   it.setValue("newValue");
++     *   Object previousKey = it.previous();
++     * }
++     * </pre>
++     *
++     * @return a map iterator
++     */
++    OrderedMapIterator<K, V> orderedMapIterator();
++
++    /**
++     * Gets the first key currently in this map.
++     *
++     * @return the first key currently in this map
++     * @throws java.util.NoSuchElementException
++     *          if this map is empty
++     */
++    public K firstKey();
++
++    /**
++     * Gets the last key currently in this map.
++     *
++     * @return the last key currently in this map
++     * @throws java.util.NoSuchElementException
++     *          if this map is empty
++     */
++    public K lastKey();
++
++    /**
++     * Gets the next key after the one specified.
++     *
++     * @param key the key to search for next from
++     * @return the next key, null if no match or at end
++     */
++    public K nextKey(K key);
++
++    /**
++     * Gets the previous key before the one specified.
++     *
++     * @param key the key to search for previous from
++     * @return the previous key, null if no match or at start
++     */
++    public K previousKey(K key);
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/OrderedMapIterator.java
+@@ -0,0 +1,46 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++/**
++ * Defines an iterator that operates over an ordered <code>Map</code>.
++ * <p/>
++ * This iterator allows both forward and reverse iteration through the map.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface OrderedMapIterator <K,V> extends MapIterator<K, V>, OrderedIterator<K> {
++
++    /**
++     * Checks to see if there is a previous entry that can be iterated to.
++     *
++     * @return <code>true</code> if the iterator has a previous element
++     */
++    boolean hasPrevious();
++
++    /**
++     * Gets the previous <em>key</em> from the <code>Map</code>.
++     *
++     * @return the previous key in the iteration
++     * @throws java.util.NoSuchElementException
++     *          if the iteration is finished
++     */
++    K previous();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/Predicate.java
+@@ -0,0 +1,49 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++/**
++ * Defines a functor interface implemented by classes that perform a predicate
++ * test on an object.
++ * <p/>
++ * A <code>Predicate</code> is the object equivalent of an <code>if</code> statement.
++ * It uses the input object to return a true or false value, and is often used in
++ * validation or filtering.
++ * <p/>
++ * Standard implementations of common predicates are provided by
++ * {@link PredicateUtils}. These include true, false, instanceof, equals, and,
++ * or, not, method invokation and null testing.
++ *
++ * @author James Strachan
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 1.0
++ */
++public interface Predicate <T> {
++
++    /**
++     * Use the specified parameter to perform a test that returns true or false.
++     *
++     * @param object the object to evaluate, should not be changed
++     * @return true or false
++     * @throws ClassCastException       (runtime) if the input is the wrong class
++     * @throws IllegalArgumentException (runtime) if the input is invalid
++     * @throws FunctorException         (runtime) if the predicate encounters a problem
++     */
++    public boolean evaluate(T object);
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/PredicateUtils.java
+@@ -0,0 +1,488 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.functors.*;
++
++import java.util.Collection;
++
++/**
++ * <code>PredicateUtils</code> provides reference implementations and utilities
++ * for the Predicate functor interface. The supplied predicates are:
++ * <ul>
++ * <li>Invoker - returns the result of a method call on the input object
++ * <li>InstanceOf - true if the object is an instanceof a class
++ * <li>Equal - true if the object equals() a specified object
++ * <li>Identity - true if the object == a specified object
++ * <li>Null - true if the object is null
++ * <li>NotNull - true if the object is not null
++ * <li>Unique - true if the object has not already been evaluated
++ * <li>And/All - true if all of the predicates are true
++ * <li>Or/Any - true if any of the predicates is true
++ * <li>Either/One - true if only one of the predicate is true
++ * <li>Neither/None - true if none of the predicates are true
++ * <li>Not - true if the predicate is false, and vice versa
++ * <li>Transformer - wraps a Transformer as a Predicate
++ * <li>True - always return true
++ * <li>False - always return false
++ * <li>Exception - always throws an exception
++ * <li>NullIsException/NullIsFalse/NullIsTrue - check for null input
++ * <li>Transformed - transforms the input before calling the predicate
++ * </ul>
++ * All the supplied predicates are Serializable.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Ola Berg
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class PredicateUtils {
++
++    /**
++     * This class is not normally instantiated.
++     */
++    public PredicateUtils() {
++        super();
++    }
++
++    // Simple predicates
++    //-----------------------------------------------------------------------------
++
++    /**
++     * Gets a Predicate that always throws an exception.
++     * This could be useful during testing as a placeholder.
++     *
++     * @return the predicate
++     * @see org.apache.commons.collections15.functors.ExceptionPredicate
++     */
++    public static Predicate exceptionPredicate() {
++        return ExceptionPredicate.INSTANCE;
++    }
++
++    /**
++     * Gets a Predicate that always returns true.
++     *
++     * @return the predicate
++     * @see org.apache.commons.collections15.functors.TruePredicate
++     */
++    public static <T> Predicate<T> truePredicate() {
++        return TruePredicate.getInstance();
++    }
++
++    /**
++     * Gets a Predicate that always returns false.
++     *
++     * @return the predicate
++     * @see org.apache.commons.collections15.functors.FalsePredicate
++     */
++    public static <T> Predicate<T> falsePredicate() {
++        return FalsePredicate.getInstance();
++    }
++
++    /**
++     * Gets a Predicate that checks if the input object passed in is null.
++     *
++     * @return the predicate
++     * @see org.apache.commons.collections15.functors.NullPredicate
++     */
++    public static <T> Predicate<T> nullPredicate() {
++        return NullPredicate.getInstance();
++    }
++
++    /**
++     * Gets a Predicate that checks if the input object passed in is not null.
++     *
++     * @return the predicate
++     * @see org.apache.commons.collections15.functors.NotNullPredicate
++     */
++    public static <T> Predicate<T> notNullPredicate() {
++        return NotNullPredicate.getInstance();
++    }
++
++    /**
++     * Creates a Predicate that checks if the input object is equal to the
++     * specified object using equals().
++     *
++     * @param value the value to compare against
++     * @return the predicate
++     * @see org.apache.commons.collections15.functors.EqualPredicate
++     */
++    public static <T> Predicate<T> equalPredicate(T value) {
++        return EqualPredicate.getInstance(value);
++    }
++
++    /**
++     * Creates a Predicate that checks if the input object is equal to the
++     * specified object by identity.
++     *
++     * @param value the value to compare against
++     * @return the predicate
++     * @see org.apache.commons.collections15.functors.IdentityPredicate
++     */
++    public static <T> Predicate<T> identityPredicate(T value) {
++        return IdentityPredicate.getInstance(value);
++    }
++
++    /**
++     * Creates a Predicate that checks if the object passed in is of
++     * a particular type, using instanceof. A <code>null</code> input
++     * object will return <code>false</code>.
++     *
++     * @param type the type to check for, may not be null
++     * @return the predicate
++     * @throws IllegalArgumentException if the class is null
++     * @see org.apache.commons.collections15.functors.InstanceofPredicate
++     */
++    @SuppressWarnings("unchecked")
++    public static Predicate instanceofPredicate(Class type) {
++        return InstanceofPredicate.getInstance(type);
++    }
++
++    /**
++     * Creates a Predicate that returns true the first time an object is
++     * encountered, and false if the same object is received
++     * again. The comparison is by equals(). A <code>null</code> input object
++     * is accepted and will return true the first time, and false subsequently
++     * as well.
++     *
++     * @return the predicate
++     * @see org.apache.commons.collections15.functors.UniquePredicate
++     */
++    public static <T> Predicate<T> uniquePredicate() {
++        // must return new instance each time
++        return UniquePredicate.getInstance();
++    }
++
++    /**
++     * Creates a Predicate that invokes a method on the input object.
++     * The method must return either a boolean or a non-null Boolean,
++     * and have no parameters. If the input object is null, a
++     * PredicateException is thrown.
++     * <p/>
++     * For example, <code>PredicateUtils.invokerPredicate("isEmpty");</code>
++     * will call the <code>isEmpty</code> method on the input object to
++     * determine the predicate result.
++     *
++     * @param methodName the method name to call on the input object, may not be null
++     * @return the predicate
++     * @throws IllegalArgumentException if the methodName is null.
++     * @see org.apache.commons.collections15.functors.InvokerTransformer
++     * @see org.apache.commons.collections15.functors.TransformerPredicate
++     */
++    public static Predicate invokerPredicate(String methodName) {
++        // reuse transformer as it has caching - this is lazy really, should have inner class here
++        return asPredicate(InvokerTransformer.getInstance(methodName));
++    }
++
++    /**
++     * Creates a Predicate that invokes a method on the input object.
++     * The method must return either a boolean or a non-null Boolean,
++     * and have no parameters. If the input object is null, a
++     * PredicateException is thrown.
++     * <p/>
++     * For example, <code>PredicateUtils.invokerPredicate("isEmpty");</code>
++     * will call the <code>isEmpty</code> method on the input object to
++     * determine the predicate result.
++     *
++     * @param methodName the method name to call on the input object, may not be null
++     * @param paramTypes the parameter types
++     * @param args       the arguments
++     * @return the predicate
++     * @throws IllegalArgumentException if the method name is null
++     * @throws IllegalArgumentException if the paramTypes and args don't match
++     * @see org.apache.commons.collections15.functors.InvokerTransformer
++     * @see org.apache.commons.collections15.functors.TransformerPredicate
++     */
++    public static Predicate invokerPredicate(String methodName, Class[] paramTypes, Object[] args) {
++        // reuse transformer as it has caching - this is lazy really, should have inner class here
++        return asPredicate(InvokerTransformer.getInstance(methodName, paramTypes, args));
++    }
++
++    // Boolean combinations
++    //-----------------------------------------------------------------------------
++
++    /**
++     * Create a new Predicate that returns true only if both of the specified
++     * predicates are true.
++     *
++     * @param predicate1 the first predicate, may not be null
++     * @param predicate2 the second predicate, may not be null
++     * @return the <code>and</code> predicate
++     * @throws IllegalArgumentException if either predicate is null
++     * @see org.apache.commons.collections15.functors.AndPredicate
++     */
++    public static <T> Predicate<T> andPredicate(Predicate<? super T> predicate1, Predicate<? super T> predicate2) {
++        return AndPredicate.<T>getInstance(predicate1, predicate2);
++    }
++
++    /**
++     * Create a new Predicate that returns true only if all of the specified
++     * predicates are true.
++     *
++     * @param predicates an array of predicates to check, may not be null
++     * @return the <code>all</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the array is null
++     * @see org.apache.commons.collections15.functors.AllPredicate
++     */
++    public static <T> Predicate<T> allPredicate(Predicate<? super T> ... predicates) {
++        return AllPredicate.getInstance(predicates);
++    }
++
++    /**
++     * Create a new Predicate that returns true only if all of the specified
++     * predicates are true. The predicates are checked in iterator order.
++     *
++     * @param predicates a collection of predicates to check, may not be null
++     * @return the <code>all</code> predicate
++     * @throws IllegalArgumentException if the predicates collection is null
++     * @throws IllegalArgumentException if the predicates collection has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the collection is null
++     * @see org.apache.commons.collections15.functors.AllPredicate
++     */
++    public static <T> Predicate<T> allPredicate(Collection<Predicate<? super T>> predicates) {
++        return AllPredicate.getInstance(predicates);
++    }
++
++    /**
++     * Create a new Predicate that returns true if either of the specified
++     * predicates are true.
++     *
++     * @param predicate1 the first predicate, may not be null
++     * @param predicate2 the second predicate, may not be null
++     * @return the <code>or</code> predicate
++     * @throws IllegalArgumentException if either predicate is null
++     * @see org.apache.commons.collections15.functors.OrPredicate
++     */
++    public static <T> Predicate<T> orPredicate(Predicate<? super T> predicate1, Predicate<? super T> predicate2) {
++        return OrPredicate.<T>getInstance(predicate1, predicate2);
++    }
++
++    /**
++     * Create a new Predicate that returns true if any of the specified
++     * predicates are true.
++     *
++     * @param predicates an array of predicates to check, may not be null
++     * @return the <code>any</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the array is null
++     * @see org.apache.commons.collections15.functors.AnyPredicate
++     */
++    public static <T> Predicate<T> anyPredicate(Predicate<? super T> ... predicates) {
++        return AnyPredicate.getInstance(predicates);
++    }
++
++    /**
++     * Create a new Predicate that returns true if any of the specified
++     * predicates are true. The predicates are checked in iterator order.
++     *
++     * @param predicates a collection of predicates to check, may not be null
++     * @return the <code>any</code> predicate
++     * @throws IllegalArgumentException if the predicates collection is null
++     * @throws IllegalArgumentException if the predicates collection has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the collection is null
++     * @see org.apache.commons.collections15.functors.AnyPredicate
++     */
++    public static <T> Predicate<T> anyPredicate(Collection<Predicate<? super T>> predicates) {
++        return AnyPredicate.getInstance(predicates);
++    }
++
++    /**
++     * Create a new Predicate that returns true if one, but not both, of the
++     * specified predicates are true.
++     *
++     * @param predicate1 the first predicate, may not be null
++     * @param predicate2 the second predicate, may not be null
++     * @return the <code>either</code> predicate
++     * @throws IllegalArgumentException if either predicate is null
++     * @see org.apache.commons.collections15.functors.OnePredicate
++     */
++    @SuppressWarnings("unchecked")
++    public static <T> Predicate<T> eitherPredicate(Predicate<? super T> predicate1, Predicate<? super T> predicate2) {
++        return onePredicate(new Predicate[]{predicate1, predicate2});
++    }
++
++    /**
++     * Create a new Predicate that returns true if only one of the specified
++     * predicates are true.
++     *
++     * @param predicates an array of predicates to check, may not be null
++     * @return the <code>one</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the array is null
++     * @see org.apache.commons.collections15.functors.OnePredicate
++     */
++    public static <T> Predicate<T> onePredicate(Predicate<? super T> ... predicates) {
++        return OnePredicate.getInstance(predicates);
++    }
++
++    /**
++     * Create a new Predicate that returns true if only one of the specified
++     * predicates are true. The predicates are checked in iterator order.
++     *
++     * @param predicates a collection of predicates to check, may not be null
++     * @return the <code>one</code> predicate
++     * @throws IllegalArgumentException if the predicates collection is null
++     * @throws IllegalArgumentException if the predicates collection has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the collection is null
++     * @see org.apache.commons.collections15.functors.OnePredicate
++     */
++    public static <T> Predicate<T> onePredicate(Collection<Predicate<? super T>> predicates) {
++        return OnePredicate.getInstance(predicates);
++    }
++
++    /**
++     * Create a new Predicate that returns true if neither of the specified
++     * predicates are true.
++     *
++     * @param predicate1 the first predicate, may not be null
++     * @param predicate2 the second predicate, may not be null
++     * @return the <code>neither</code> predicate
++     * @throws IllegalArgumentException if either predicate is null
++     * @see org.apache.commons.collections15.functors.NonePredicate
++     */
++    @SuppressWarnings("unchecked")
++    public static <T> Predicate<T> neitherPredicate(Predicate<? super T> predicate1, Predicate<? super T> predicate2) {
++        return nonePredicate(new Predicate[]{predicate1, predicate2});
++    }
++
++    /**
++     * Create a new Predicate that returns true if none of the specified
++     * predicates are true.
++     *
++     * @param predicates an array of predicates to check, may not be null
++     * @return the <code>none</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the array is null
++     * @see org.apache.commons.collections15.functors.NonePredicate
++     */
++    public static <T> Predicate<T> nonePredicate(Predicate<? super T> ... predicates) {
++        return NonePredicate.getInstance(predicates);
++    }
++
++    /**
++     * Create a new Predicate that returns true if none of the specified
++     * predicates are true. The predicates are checked in iterator order.
++     *
++     * @param predicates a collection of predicates to check, may not be null
++     * @return the <code>none</code> predicate
++     * @throws IllegalArgumentException if the predicates collection is null
++     * @throws IllegalArgumentException if the predicates collection has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the collection is null
++     * @see org.apache.commons.collections15.functors.NonePredicate
++     */
++    public static <T> Predicate<T> nonePredicate(Collection<Predicate<? super T>> predicates) {
++        return NonePredicate.getInstance(predicates);
++    }
++
++    /**
++     * Create a new Predicate that returns true if the specified predicate
++     * returns false and vice versa.
++     *
++     * @param predicate the predicate to not
++     * @return the <code>not</code> predicate
++     * @throws IllegalArgumentException if the predicate is null
++     * @see org.apache.commons.collections15.functors.NotPredicate
++     */
++    public static <T> Predicate<T> notPredicate(Predicate<T> predicate) {
++        return NotPredicate.getInstance(predicate);
++    }
++
++    // Adaptors
++    //-----------------------------------------------------------------------------
++
++    /**
++     * Create a new Predicate that wraps a Transformer. The Transformer must
++     * return either Boolean.TRUE or Boolean.FALSE otherwise a PredicateException
++     * will be thrown.
++     *
++     * @param transformer the transformer to wrap, may not be null
++     * @return the transformer wrapping predicate
++     * @throws IllegalArgumentException if the transformer is null
++     * @see org.apache.commons.collections15.functors.TransformerPredicate
++     */
++    public static <T> Predicate<T> asPredicate(Transformer<T, Boolean> transformer) {
++        return TransformerPredicate.getInstance(transformer);
++    }
++
++    // Null handlers
++    //-----------------------------------------------------------------------------
++
++    /**
++     * Gets a Predicate that throws an exception if the input object is null,
++     * otherwise it calls the specified Predicate. This allows null handling
++     * behaviour to be added to Predicates that don't support nulls.
++     *
++     * @param predicate the predicate to wrap, may not be null
++     * @return the predicate
++     * @throws IllegalArgumentException if the predicate is null.
++     * @see org.apache.commons.collections15.functors.NullIsExceptionPredicate
++     */
++    public static <T> Predicate<T> nullIsExceptionPredicate(Predicate<T> predicate) {
++        return NullIsExceptionPredicate.getInstance(predicate);
++    }
++
++    /**
++     * Gets a Predicate that returns false if the input object is null, otherwise
++     * it calls the specified Predicate. This allows null handling behaviour to
++     * be added to Predicates that don't support nulls.
++     *
++     * @param predicate the predicate to wrap, may not be null
++     * @return the predicate
++     * @throws IllegalArgumentException if the predicate is null.
++     * @see org.apache.commons.collections15.functors.NullIsFalsePredicate
++     */
++    public static <T> Predicate<T> nullIsFalsePredicate(Predicate<T> predicate) {
++        return NullIsFalsePredicate.getInstance(predicate);
++    }
++
++    /**
++     * Gets a Predicate that returns true if the input object is null, otherwise
++     * it calls the specified Predicate. This allows null handling behaviour to
++     * be added to Predicates that don't support nulls.
++     *
++     * @param predicate the predicate to wrap, may not be null
++     * @return the predicate
++     * @throws IllegalArgumentException if the predicate is null.
++     * @see org.apache.commons.collections15.functors.NullIsTruePredicate
++     */
++    public static <T> Predicate<T> nullIsTruePredicate(Predicate<T> predicate) {
++        return NullIsTruePredicate.getInstance(predicate);
++    }
++
++    // Transformed
++    //-----------------------------------------------------------------------
++    /**
++     * Creates a predicate that transforms the input object before passing it
++     * to the predicate.
++     *
++     * @param transformer the transformer to call first
++     * @param predicate   the predicate to call with the result of the transform
++     * @return the predicate
++     * @throws IllegalArgumentException if the transformer or the predicate is null
++     * @see org.apache.commons.collections15.functors.TransformedPredicate
++     * @since Commons Collections 3.1
++     */
++    public static <I,O> Predicate<I> transformedPredicate(Transformer<I, ? extends O> transformer, Predicate<? super O> predicate) {
++        return TransformedPredicate.getInstance(transformer, predicate);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/ResettableIterator.java
+@@ -0,0 +1,38 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.Iterator;
++
++/**
++ * Defines an iterator that can be reset back to an initial state.
++ * <p/>
++ * This interface allows an iterator to be repeatedly reused.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface ResettableIterator <E> extends Iterator<E> {
++
++    /**
++     * Resets the iterator back to the position at which the iterator
++     * was created.
++     */
++    public void reset();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/ResettableListIterator.java
+@@ -0,0 +1,38 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.ListIterator;
++
++/**
++ * Defines a list iterator that can be reset back to an initial state.
++ * <p/>
++ * This interface allows an iterator to be repeatedly reused.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface ResettableListIterator <E> extends ListIterator<E>, ResettableIterator<E> {
++
++    /**
++     * Resets the iterator back to the position at which the iterator
++     * was created.
++     */
++    public void reset();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/SetUtils.java
+@@ -0,0 +1,312 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.set.*;
++
++import java.util.*;
++
++/**
++ * Provides utility methods and decorators for
++ * {@link Set} and {@link SortedSet} instances.
++ *
++ * @author Paul Jack
++ * @author Stephen Colebourne
++ * @author Neil O'Toole
++ * @author Matt Hall, John Watkinson, Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.1
++ */
++public class SetUtils {
++
++    /**
++     * An empty unmodifiable set.
++     * This uses the {@link Collections} implementation
++     * and is provided for completeness.
++     */
++    public static final Set EMPTY_SET = Collections.EMPTY_SET;
++    /**
++     * An empty unmodifiable sorted set.
++     * This is not provided in the JDK.
++     */
++    public static final SortedSet EMPTY_SORTED_SET = UnmodifiableSortedSet.decorate(new TreeSet());
++
++    /**
++     * <code>SetUtils</code> should not normally be instantiated.
++     */
++    public SetUtils() {
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Tests two sets for equality as per the <code>equals()</code> contract
++     * in {@link java.util.Set#equals(java.lang.Object)}.
++     * <p/>
++     * This method is useful for implementing <code>Set</code> when you cannot
++     * extend AbstractSet. The method takes Collection instances to enable other
++     * collection types to use the Set implementation algorithm.
++     * <p/>
++     * The relevant text (slightly paraphrased as this is a static method) is:
++     * <blockquote>
++     * <p>Two sets are considered equal if they have
++     * the same size, and every member of the first set is contained in
++     * the second. This ensures that the <tt>equals</tt> method works
++     * properly across different implementations of the <tt>Set</tt>
++     * interface.</p>
++     * <p/>
++     * <p/>
++     * This implementation first checks if the two sets are the same object:
++     * if so it returns <tt>true</tt>.  Then, it checks if the two sets are
++     * identical in size; if not, it returns false. If so, it returns
++     * <tt>a.containsAll((Collection) b)</tt>.</p>
++     * </blockquote>
++     *
++     * @param set1 the first set, may be null
++     * @param set2 the second set, may be null
++     * @return whether the sets are equal by value comparison
++     * @see java.util.Set
++     */
++    public static boolean isEqualSet(final Collection set1, final Collection set2) {
++        if (set1 == set2) {
++            return true;
++        }
++        if (set1 == null || set2 == null || set1.size() != set2.size()) {
++            return false;
++        }
++
++        return set1.containsAll(set2);
++    }
++
++    /**
++     * Generates a hash code using the algorithm specified in
++     * {@link java.util.Set#hashCode()}.
++     * <p/>
++     * This method is useful for implementing <code>Set</code> when you cannot
++     * extend AbstractSet. The method takes Collection instances to enable other
++     * collection types to use the Set implementation algorithm.
++     *
++     * @param set the set to calculate the hash code for, may be null
++     * @return the hash code
++     * @see java.util.Set#hashCode()
++     */
++    public static int hashCodeForSet(final Collection set) {
++        if (set == null) {
++            return 0;
++        }
++        int hashCode = 0;
++        Iterator it = set.iterator();
++        Object obj = null;
++
++        while (it.hasNext()) {
++            obj = it.next();
++            if (obj != null) {
++                hashCode += obj.hashCode();
++            }
++        }
++        return hashCode;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a synchronized set backed by the given set.
++     * <p/>
++     * You must manually synchronize on the returned buffer's iterator to
++     * avoid non-deterministic behavior:
++     * <p/>
++     * <pre>
++     * Set s = SetUtils.synchronizedSet(mySet);
++     * synchronized (s) {
++     *     Iterator i = s.iterator();
++     *     while (i.hasNext()) {
++     *         process (i.next());
++     *     }
++     * }
++     * </pre>
++     * <p/>
++     * This method uses the implementation in the decorators subpackage.
++     *
++     * @param set the set to synchronize, must not be null
++     * @return a synchronized set backed by the given set
++     * @throws IllegalArgumentException if the set is null
++     */
++    public static <E> Set<E> synchronizedSet(Set<E> set) {
++        return SynchronizedSet.decorate(set);
++    }
++
++    /**
++     * Returns an unmodifiable set backed by the given set.
++     * <p/>
++     * This method uses the implementation in the decorators subpackage.
++     *
++     * @param set the set to make unmodifiable, must not be null
++     * @return an unmodifiable set backed by the given set
++     * @throws IllegalArgumentException if the set is null
++     */
++    public static <E> Set<E> unmodifiableSet(Set<E> set) {
++        return UnmodifiableSet.decorate(set);
++    }
++
++    /**
++     * Returns a predicated (validating) set backed by the given set.
++     * <p/>
++     * Only objects that pass the test in the given predicate can be added to the set.
++     * Trying to add an invalid object results in an IllegalArgumentException.
++     * It is important not to use the original set after invoking this method,
++     * as it is a backdoor for adding invalid objects.
++     *
++     * @param set       the set to predicate, must not be null
++     * @param predicate the predicate for the set, must not be null
++     * @return a predicated set backed by the given set
++     * @throws IllegalArgumentException if the Set or Predicate is null
++     */
++    public static <E> Set<E> predicatedSet(Set<E> set, Predicate<? super E> predicate) {
++        return PredicatedSet.decorate(set, predicate);
++    }
++
++    /**
++     * Returns a typed set backed by the given set.
++     * <p/>
++     * Only objects of the specified type can be added to the set.
++     *
++     * @param set  the set to limit to a specific type, must not be null
++     * @param type the type of objects which may be added to the set
++     * @return a typed set backed by the specified set
++     * @deprecated Made obsolete by Java 1.5 generics.
++     */
++    public static <E> Set<E> typedSet(Set<E> set, Class<E> type) {
++        return TypedSet.decorate(set, type);
++    }
++
++    /**
++     * Returns a transformed set backed by the given set.
++     * <p/>
++     * Each object is passed through the transformer as it is added to the
++     * Set. It is important not to use the original set after invoking this
++     * method, as it is a backdoor for adding untransformed objects.
++     *
++     * @param set         the set to transform, must not be null
++     * @param transformer the transformer for the set, must not be null
++     * @return a transformed set backed by the given set
++     * @throws IllegalArgumentException if the Set or Transformer is null
++     */
++    public static <I,O> Set<O> transformedSet(Set<I> set, Transformer<? super I, ? extends O> transformer) {
++        return TransformedSet.decorate(set, transformer);
++    }
++
++    /**
++     * Returns a set that maintains the order of elements that are added
++     * backed by the given set.
++     * <p/>
++     * If an element is added twice, the order is determined by the first add.
++     * The order is observed through the iterator or toArray.
++     *
++     * @param set the set to order, must not be null
++     * @return an ordered set backed by the given set
++     * @throws IllegalArgumentException if the Set is null
++     */
++    public static <E> Set<E> orderedSet(Set<E> set) {
++        return ListOrderedSet.decorate(set);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a synchronized sorted set backed by the given sorted set.
++     * <p/>
++     * You must manually synchronize on the returned buffer's iterator to
++     * avoid non-deterministic behavior:
++     * <p/>
++     * <pre>
++     * Set s = SetUtils.synchronizedSet(mySet);
++     * synchronized (s) {
++     *     Iterator i = s.iterator();
++     *     while (i.hasNext()) {
++     *         process (i.next());
++     *     }
++     * }
++     * </pre>
++     * <p/>
++     * This method uses the implementation in the decorators subpackage.
++     *
++     * @param set the sorted set to synchronize, must not be null
++     * @return a synchronized set backed by the given set
++     * @throws IllegalArgumentException if the set is null
++     */
++    public static <E> SortedSet<E> synchronizedSortedSet(SortedSet<E> set) {
++        return SynchronizedSortedSet.decorate(set);
++    }
++
++    /**
++     * Returns an unmodifiable sorted set backed by the given sorted set.
++     * <p/>
++     * This method uses the implementation in the decorators subpackage.
++     *
++     * @param set the sorted set to make unmodifiable, must not be null
++     * @return an unmodifiable set backed by the given set
++     * @throws IllegalArgumentException if the set is null
++     */
++    public static <E> SortedSet<E> unmodifiableSortedSet(SortedSet<E> set) {
++        return UnmodifiableSortedSet.decorate(set);
++    }
++
++    /**
++     * Returns a predicated (validating) sorted set backed by the given sorted set.
++     * <p/>
++     * Only objects that pass the test in the given predicate can be added to the set.
++     * Trying to add an invalid object results in an IllegalArgumentException.
++     * It is important not to use the original set after invoking this method,
++     * as it is a backdoor for adding invalid objects.
++     *
++     * @param set       the sorted set to predicate, must not be null
++     * @param predicate the predicate for the sorted set, must not be null
++     * @return a predicated sorted set backed by the given sorted set
++     * @throws IllegalArgumentException if the Set or Predicate is null
++     */
++    public static <E> SortedSet<E> predicatedSortedSet(SortedSet<E> set, Predicate<? super E> predicate) {
++        return PredicatedSortedSet.decorate(set, predicate);
++    }
++
++    /**
++     * Returns a typed sorted set backed by the given set.
++     * <p/>
++     * Only objects of the specified type can be added to the set.
++     *
++     * @param set  the set to limit to a specific type, must not be null
++     * @param type the type of objects which may be added to the set
++     * @return a typed set backed by the specified set
++     * @deprecated made obsolete by Java 1.5 generics.
++     */
++    public static <E> SortedSet<E> typedSortedSet(SortedSet<E> set, Class<E> type) {
++        return TypedSortedSet.decorate(set, type);
++    }
++
++    /**
++     * Returns a transformed sorted set backed by the given set.
++     * <p/>
++     * Each object is passed through the transformer as it is added to the
++     * Set. It is important not to use the original set after invoking this
++     * method, as it is a backdoor for adding untransformed objects.
++     *
++     * @param set         the set to transform, must not be null
++     * @param transformer the transformer for the set, must not be null
++     * @return a transformed set backed by the given set
++     * @throws IllegalArgumentException if the Set or Transformer is null
++     */
++    public static <I,O> SortedSet<O> transformedSortedSet(SortedSet<I> set, Transformer<? super I, ? extends O> transformer) {
++        return TransformedSortedSet.decorate(set, transformer);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/SortedBag.java
+@@ -0,0 +1,53 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.Comparator;
++
++/**
++ * Defines a type of <code>Bag</code> that maintains a sorted order among
++ * its unique representative members.
++ *
++ * @author Matt Hall, John Watkinson, Chuck Burdick
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 2.0
++ */
++public interface SortedBag <E> extends Bag<E> {
++
++    /**
++     * Returns the comparator associated with this sorted set, or null
++     * if it uses its elements' natural ordering.
++     *
++     * @return the comparator in use, or null if natural ordering
++     */
++    public Comparator<? super E> comparator();
++
++    /**
++     * Returns the first (lowest) member.
++     *
++     * @return the first element in the sorted bag
++     */
++    public E first();
++
++    /**
++     * Returns the last (highest) member.
++     *
++     * @return the last element in the sorted bag
++     */
++    public E last();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/SortedBidiMap.java
+@@ -0,0 +1,68 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import java.util.SortedMap;
++
++/**
++ * Defines a map that allows bidirectional lookup between key and values
++ * and retains both keys and values in sorted order.
++ * <p/>
++ * Implementations should allow a value to be looked up from a key and
++ * a key to be looked up from a value with equal performance.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface SortedBidiMap <K,V> extends OrderedBidiMap<K, V>, SortedMap<K, V> {
++
++    /**
++     * Gets a view of this map where the keys and values are reversed.
++     * <p/>
++     * Changes to one map will be visible in the other and vice versa.
++     * This enables both directions of the map to be accessed equally.
++     * <p/>
++     * Implementations should seek to avoid creating a new object every time this
++     * method is called. See <code>AbstractMap.values()</code> etc. Calling this
++     * method on the inverse map should return the original.
++     * <p/>
++     * Implementations must return a <code>SortedBidiMap</code> instance,
++     * usually by forwarding to <code>inverseSortedBidiMap()</code>.
++     *
++     * @return an inverted bidirectional map
++     */
++    public BidiMap<V, K> inverseBidiMap();
++
++    /**
++     * Gets a view of this map where the keys and values are reversed.
++     * <p/>
++     * Changes to one map will be visible in the other and vice versa.
++     * This enables both directions of the map to be accessed as a <code>SortedMap</code>.
++     * <p/>
++     * Implementations should seek to avoid creating a new object every time this
++     * method is called. See <code>AbstractMap.values()</code> etc. Calling this
++     * method on the inverse map should return the original.
++     * <p/>
++     * The inverse map returned by <code>inverseBidiMap()</code> should be the
++     * same object as returned by this method.
++     *
++     * @return an inverted bidirectional map
++     */
++    public SortedBidiMap<V, K> inverseSortedBidiMap();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/Transformer.java
+@@ -0,0 +1,50 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++/**
++ * Defines a functor interface implemented by classes that transform one
++ * object into another.
++ * <p/>
++ * A <code>Transformer</code> converts the input object to the output object.
++ * The input object should be left unchanged.
++ * Transformers are typically used for type conversions, or extracting data
++ * from an object.
++ * <p/>
++ * Standard implementations of common transformers are provided by
++ * {@link TransformerUtils}. These include method invokation, returning a constant,
++ * cloning and returning the string value.
++ *
++ * @author James Strachan
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 1.0
++ */
++public interface Transformer <I,O> {
++
++    /**
++     * Transforms the input object (leaving it unchanged) into some output object.
++     *
++     * @param input the object to be transformed, should be left unchanged
++     * @return a transformed object
++     * @throws ClassCastException       (runtime) if the input is the wrong class
++     * @throws IllegalArgumentException (runtime) if the input is invalid
++     * @throws FunctorException         (runtime) if the transform cannot be completed
++     */
++    public O transform(I input);
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/TransformerUtils.java
+@@ -0,0 +1,414 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++import org.apache.commons.collections15.functors.*;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Map;
++
++/**
++ * <code>TransformerUtils</code> provides reference implementations and
++ * utilities for the Transformer functor interface. The supplied transformers are:
++ * <ul>
++ * <li>Invoker - returns the result of a method call on the input object
++ * <li>Clone - returns a clone of the input object
++ * <li>Constant - always returns the same object
++ * <li>Closure - performs a Closure and returns the input object
++ * <li>Predicate - returns the result of the predicate as a Boolean
++ * <li>Factory - returns a new object from a factory
++ * <li>Chained - chains two or more transformers together
++ * <li>Switch - calls one transformer based on one or more predicates
++ * <li>SwitchMap - calls one transformer looked up from a Map
++ * <li>Instantiate - the Class input object is instantiated
++ * <li>Map - returns an object from a supplied Map
++ * <li>Null - always returns null
++ * <li>NOP - returns the input object, which should be immutable
++ * <li>Exception - always throws an exception
++ * <li>StringValue - returns a <code>java.lang.String</code> representation of the input object
++ * </ul>
++ * All the supplied transformers are Serializable.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, James Carman
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class TransformerUtils {
++
++    /**
++     * This class is not normally instantiated.
++     */
++    public TransformerUtils() {
++        super();
++    }
++
++    /**
++     * Gets a transformer that always throws an exception.
++     * This could be useful during testing as a placeholder.
++     *
++     * @return the transformer
++     * @see org.apache.commons.collections15.functors.ExceptionTransformer
++     */
++    public static Transformer exceptionTransformer() {
++        return ExceptionTransformer.INSTANCE;
++    }
++
++    /**
++     * Gets a transformer that always returns null.
++     *
++     * @return the transformer
++     * @see org.apache.commons.collections15.functors.ConstantTransformer
++     */
++    public static Transformer nullTransformer() {
++        return ConstantTransformer.NULL_INSTANCE;
++    }
++
++    /**
++     * Gets a transformer that returns the input object.
++     * The input object should be immutable to maintain the
++     * contract of Transformer (although this is not checked).
++     *
++     * @return the transformer
++     * @see org.apache.commons.collections15.functors.NOPTransformer
++     */
++    public static Transformer nopTransformer() {
++        return NOPTransformer.INSTANCE;
++    }
++
++    /**
++     * Gets a transformer that returns a clone of the input
++     * object. The input object will be cloned using one of these
++     * techniques (in order):
++     * <ul>
++     * <li>public clone method
++     * <li>public copy constructor
++     * <li>serialization clone
++     * <ul>
++     *
++     * @return the transformer
++     * @see org.apache.commons.collections15.functors.CloneTransformer
++     */
++    public static Transformer cloneTransformer() {
++        return CloneTransformer.INSTANCE;
++    }
++
++    /**
++     * Creates a Transformer that will return the same object each time the
++     * transformer is used.
++     *
++     * @param constantToReturn the constant object to return each time in the transformer
++     * @return the transformer.
++     * @see org.apache.commons.collections15.functors.ConstantTransformer
++     */
++    public static <T> Transformer<Object, T> constantTransformer(T constantToReturn) {
++        return ConstantTransformer.getInstance(constantToReturn);
++    }
++
++    /**
++     * Creates a Transformer that calls a Closure each time the transformer is used.
++     * The transformer returns the input object.
++     *
++     * @param closure the closure to run each time in the transformer, not null
++     * @return the transformer
++     * @throws IllegalArgumentException if the closure is null
++     * @see org.apache.commons.collections15.functors.ClosureTransformer
++     */
++    public static <T> Transformer<T, T> asTransformer(Closure<T> closure) {
++        return ClosureTransformer.getInstance(closure);
++    }
++
++    /**
++     * Creates a Transformer that calls a Predicate each time the transformer is used.
++     * The transformer will return either Boolean.TRUE or Boolean.FALSE.
++     *
++     * @param predicate the predicate to run each time in the transformer, not null
++     * @return the transformer
++     * @throws IllegalArgumentException if the predicate is null
++     * @see org.apache.commons.collections15.functors.PredicateTransformer
++     */
++    public static <T> Transformer<T, Boolean> asTransformer(Predicate<T> predicate) {
++        return PredicateTransformer.getInstance(predicate);
++    }
++
++    /**
++     * Creates a Transformer that calls a Factory each time the transformer is used.
++     * The transformer will return the value returned by the factory.
++     *
++     * @param factory the factory to run each time in the transformer, not null
++     * @return the transformer
++     * @throws IllegalArgumentException if the factory is null
++     * @see org.apache.commons.collections15.functors.FactoryTransformer
++     */
++    public static <T> Transformer<Object, T> asTransformer(Factory<T> factory) {
++        return FactoryTransformer.getInstance(factory);
++    }
++
++    /**
++     * Create a new Transformer that calls two transformers, passing the result of
++     * the first into the second.
++     *
++     * @param transformer1 the first transformer
++     * @param transformer2 the second transformer
++     * @return the transformer
++     * @throws IllegalArgumentException if either transformer is null
++     * @see org.apache.commons.collections15.functors.ChainedTransformer
++     */
++    public static <I,M,O> Transformer<I, O> chainedTransformer(Transformer<I, ? extends M> transformer1, Transformer<? super M, O> transformer2) {
++        return ChainedTransformer.getInstance(transformer1, transformer2);
++    }
++
++    /**
++     * Create a new Transformer that calls each transformer in turn, passing the
++     * result into the next transformer.
++     * <p/>
++     * Note-- no type safety provided by generics.
++     *
++     * @param transformers an array of transformers to chain
++     * @return the transformer
++     * @throws IllegalArgumentException if the transformers array is null
++     * @throws IllegalArgumentException if any transformer in the array is null
++     * @see org.apache.commons.collections15.functors.ChainedTransformer
++     */
++    public static <I,O> Transformer<I, O> chainedTransformer(Transformer[] transformers) {
++        return ChainedTransformer.getInstance(transformers);
++    }
++
++    /**
++     * Create a new Transformer that calls each transformer in turn, passing the
++     * result into the next transformer. The ordering is that of the iterator()
++     * method on the collection.
++     * <p/>
++     * Note-- no type safety provided by generics.
++     *
++     * @param transformers a collection of transformers to chain
++     * @return the transformer
++     * @throws IllegalArgumentException if the transformers collection is null
++     * @throws IllegalArgumentException if any transformer in the collection is null
++     * @see org.apache.commons.collections15.functors.ChainedTransformer
++     */
++    public static <I,O> Transformer<I, O> chainedTransformer(Collection transformers) {
++        return ChainedTransformer.getInstance(transformers);
++    }
++
++    /**
++     * Create a new Transformer that calls one of two transformers depending
++     * on the specified predicate.
++     *
++     * @param predicate        the predicate to switch on
++     * @param trueTransformer  the transformer called if the predicate is true
++     * @param falseTransformer the transformer called if the predicate is false
++     * @return the transformer
++     * @throws IllegalArgumentException if the predicate is null
++     * @throws IllegalArgumentException if either transformer is null
++     * @see org.apache.commons.collections15.functors.SwitchTransformer
++     */
++    public static <I,O> Transformer<I, O> switchTransformer(Predicate<I> predicate, Transformer<? super I, ? extends O> trueTransformer, Transformer<? super I, ? extends O> falseTransformer) {
++        return SwitchTransformer.getInstance(new Predicate[]{predicate}, new Transformer[]{trueTransformer}, falseTransformer);
++    }
++
++    /**
++     * Create a new Transformer that calls one of the transformers depending
++     * on the predicates. The transformer at array location 0 is called if the
++     * predicate at array location 0 returned true. Each predicate is evaluated
++     * until one returns true. If no predicates evaluate to true, null is returned.
++     *
++     * @param predicates   an array of predicates to check
++     * @param transformers an array of transformers to call
++     * @return the transformer
++     * @throws IllegalArgumentException if the either array is null
++     * @throws IllegalArgumentException if the either array has 0 elements
++     * @throws IllegalArgumentException if any element in the arrays is null
++     * @throws IllegalArgumentException if the arrays are different sizes
++     * @see org.apache.commons.collections15.functors.SwitchTransformer
++     */
++    public static <I,O> Transformer<I, O> switchTransformer(Predicate<? super I>[] predicates, Transformer<? super I, ? extends O>[] transformers) {
++        return SwitchTransformer.<I, O>getInstance(predicates, transformers, null);
++    }
++
++    /**
++     * Create a new Transformer that calls one of the transformers depending
++     * on the predicates. The transformer at array location 0 is called if the
++     * predicate at array location 0 returned true. Each predicate is evaluated
++     * until one returns true. If no predicates evaluate to true, the default
++     * transformer is called. If the default transformer is null, null is returned.
++     *
++     * @param predicates         an array of predicates to check
++     * @param transformers       an array of transformers to call
++     * @param defaultTransformer the default to call if no predicate matches, null means return null
++     * @return the transformer
++     * @throws IllegalArgumentException if the either array is null
++     * @throws IllegalArgumentException if the either array has 0 elements
++     * @throws IllegalArgumentException if any element in the arrays is null
++     * @throws IllegalArgumentException if the arrays are different sizes
++     * @see org.apache.commons.collections15.functors.SwitchTransformer
++     */
++    public static <I,O> Transformer<I, O> switchTransformer(Predicate<? super I>[] predicates, Transformer<? super I, ? extends O>[] transformers, Transformer<? super I, ? extends O> defaultTransformer) {
++        return SwitchTransformer.<I, O>getInstance(predicates, transformers, defaultTransformer);
++    }
++
++    /**
++     * Create a new Transformer that calls one of the transformers depending
++     * on the predicates.
++     * <p/>
++     * The Map consists of Predicate keys and Transformer values. A transformer
++     * is called if its matching predicate returns true. Each predicate is evaluated
++     * until one returns true. If no predicates evaluate to true, the default
++     * transformer is called. The default transformer is set in the map with a
++     * null key. If no default transformer is set, null will be returned in a default
++     * case. The ordering is that of the iterator() method on the entryset collection
++     * of the map.
++     *
++     * @param predicatesAndTransformers a map of predicates to transformers
++     * @return the transformer
++     * @throws IllegalArgumentException if the map is null
++     * @throws IllegalArgumentException if the map is empty
++     * @throws IllegalArgumentException if any transformer in the map is null
++     * @throws ClassCastException       if the map elements are of the wrong type
++     * @see org.apache.commons.collections15.functors.SwitchTransformer
++     */
++    public static <I,O> Transformer<I, O> switchTransformer(Map<Predicate<? super I>, Transformer<? super I, ? extends O>> predicatesAndTransformers) {
++        return SwitchTransformer.<I, O>getInstance(predicatesAndTransformers);
++    }
++
++    /**
++     * Create a new Transformer that uses the input object as a key to find the
++     * transformer to call.
++     * <p/>
++     * The Map consists of object keys and Transformer values. A transformer
++     * is called if the input object equals the key. If there is no match, the
++     * default transformer is called. The default transformer is set in the map
++     * using a null key. If no default is set, null will be returned in a default case.
++     *
++     * @param objectsAndTransformers a map of objects to transformers
++     * @return the transformer
++     * @throws IllegalArgumentException if the map is null
++     * @throws IllegalArgumentException if the map is empty
++     * @throws IllegalArgumentException if any transformer in the map is null
++     * @see org.apache.commons.collections15.functors.SwitchTransformer
++     */
++    public static <I,O> Transformer<I, O> switchMapTransformer(Map<I, Transformer<? super I, ? extends O>> objectsAndTransformers) {
++        Transformer[] trs = null;
++        Predicate[] preds = null;
++        if (objectsAndTransformers == null) {
++            throw new IllegalArgumentException("The object and transformer map must not be null");
++        }
++        Transformer<? super I, ? extends O> def = objectsAndTransformers.remove(null);
++        int size = objectsAndTransformers.size();
++        trs = new Transformer[size];
++        preds = new Predicate[size];
++        int i = 0;
++        for (Iterator<Map.Entry<I, Transformer<? super I, ? extends O>>> it = objectsAndTransformers.entrySet().iterator(); it.hasNext();) {
++            Map.Entry<I, Transformer<? super I, ? extends O>> entry = it.next();
++            preds[i] = EqualPredicate.getInstance(entry.getKey());
++            trs[i] = entry.getValue();
++            i++;
++        }
++        return switchTransformer(preds, trs, def);
++    }
++
++    /**
++     * Gets a Transformer that expects an input Class object that it will instantiate.
++     *
++     * @return the transformer
++     * @see org.apache.commons.collections15.functors.InstantiateTransformer
++     */
++    public static Transformer<Class, Object> instantiateTransformer() {
++        return InstantiateTransformer.NO_ARG_INSTANCE;
++    }
++
++    /**
++     * Creates a Transformer that expects an input Class object that it will
++     * instantiate. The constructor used is determined by the arguments specified
++     * to this method.
++     *
++     * @param paramTypes parameter types for the constructor, can be null
++     * @param args       the arguments to pass to the constructor, can be null
++     * @return the transformer
++     * @throws IllegalArgumentException if the paramTypes and args don't match
++     * @see org.apache.commons.collections15.functors.InstantiateTransformer
++     */
++    public static Transformer<Class, Object> instantiateTransformer(Class[] paramTypes, Object[] args) {
++        return InstantiateTransformer.getInstance(paramTypes, args);
++    }
++
++    /**
++     * Creates a Transformer that uses the passed in Map to transform the input
++     * object (as a simple lookup).
++     *
++     * @param map the map to use to transform the objects
++     * @return the transformer
++     * @throws IllegalArgumentException if the map is null
++     * @see org.apache.commons.collections15.functors.MapTransformer
++     */
++    public static <I,O> Transformer<I, O> mapTransformer(Map<I, O> map) {
++        return MapTransformer.getInstance(map);
++    }
++
++    /**
++     * Gets a Transformer that invokes a method on the input object.
++     * The method must have no parameters. If the input object is null,
++     * null is returned.
++     * <p/>
++     * For example, <code>TransformerUtils.invokerTransformer("getName");</code>
++     * will call the <code>getName/code> method on the input object to
++     * determine the transformer result.
++     * <p/>
++     * Note: no type saftey provided by Java 1.5.
++     *
++     * @param methodName the method name to call on the input object, may not be null
++     * @return the transformer
++     * @throws IllegalArgumentException if the methodName is null.
++     * @see org.apache.commons.collections15.functors.InvokerTransformer
++     */
++    public static Transformer invokerTransformer(String methodName) {
++        return InvokerTransformer.getInstance(methodName, null, null);
++    }
++
++    /**
++     * Gets a Transformer that invokes a method on the input object.
++     * The method parameters are specified. If the input object is null,
++     * null is returned.
++     * <p/>
++     * Note: no type saftey provided by Java 1.5.
++     *
++     * @param methodName the name of the method
++     * @param paramTypes the parameter types
++     * @param args       the arguments
++     * @return the transformer
++     * @throws IllegalArgumentException if the method name is null
++     * @throws IllegalArgumentException if the paramTypes and args don't match
++     * @see org.apache.commons.collections15.functors.InvokerTransformer
++     */
++    public static Transformer invokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
++        return InvokerTransformer.getInstance(methodName, paramTypes, args);
++    }
++
++    /**
++     * Gets a transformer that returns a <code>java.lang.String</code>
++     * representation of the input object. This is achieved via the
++     * <code>toString</code> method, <code>null</code> returns 'null'.
++     *
++     * @return the transformer
++     * @see org.apache.commons.collections15.functors.StringValueTransformer
++     */
++    public static <T> Transformer<T, String> stringValueTransformer() {
++        return StringValueTransformer.getInstance();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/Unmodifiable.java
+@@ -0,0 +1,39 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15;
++
++/**
++ * Marker interface for collections15, maps and iterators that are unmodifiable.
++ * <p/>
++ * This interface enables testing such as:
++ * <pre>
++ * if (coll instanceof Unmodifiable) {
++ *   coll = new ArrayList(coll);
++ * }
++ * // now we know coll is modifiable
++ * </pre>
++ * Of course all this only works if you use the Unmodifiable classes defined
++ * in this library. If you use the JDK unmodifiable class via java util Collections
++ * then the interface won't be there.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public interface Unmodifiable {
++    // marker interface - no methods to implement
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/AbstractBagDecorator.java
+@@ -0,0 +1,80 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.Bag;
++import org.apache.commons.collections15.collection.AbstractCollectionDecorator;
++
++import java.util.Set;
++
++/**
++ * Decorates another <code>Bag</code> to provide additional behaviour.
++ * <p/>
++ * Methods are forwarded directly to the decorated bag.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractBagDecorator <E> extends AbstractCollectionDecorator<E> implements Bag<E> {
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     *
++     * @since Commons Collections 3.1
++     */
++    protected AbstractBagDecorator() {
++        super();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param bag the bag to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    protected AbstractBagDecorator(Bag<E> bag) {
++        super(bag);
++    }
++
++    /**
++     * Gets the bag being decorated.
++     *
++     * @return the decorated bag
++     */
++    protected Bag<E> getBag() {
++        return (Bag<E>) getCollection();
++    }
++
++    //-----------------------------------------------------------------------
++    public int getCount(E object) {
++        return getBag().getCount(object);
++    }
++
++    public boolean add(E object, int count) {
++        return getBag().add(object, count);
++    }
++
++    public boolean remove(E object, int count) {
++        return getBag().remove(object, count);
++    }
++
++    public Set<E> uniqueSet() {
++        return getBag().uniqueSet();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/AbstractMapBag.java
+@@ -0,0 +1,600 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.Bag;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.lang.reflect.Array;
++import java.util.*;
++
++/**
++ * Abstract implementation of the {@link Bag} interface to simplify the creation
++ * of subclass implementations.
++ * <p/>
++ * Subclasses specify a Map implementation to use as the internal storage.
++ * The map will be used to map bag elements to a number; the number represents
++ * the number of occurrences of that element in the bag.
++ *
++ * @author Chuck Burdick
++ * @author Michael A. Smith
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Janek Bogucki
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0 (previously DefaultMapBag v2.0)
++ */
++public abstract class AbstractMapBag <E> implements Bag<E> {
++
++    /**
++     * The map to use to store the data
++     */
++    private transient Map<E, MutableInteger> map;
++    /**
++     * The current total size of the bag
++     */
++    private int size;
++    /**
++     * The modification count for fail fast iterators
++     */
++    private transient int modCount;
++    /**
++     * The modification count for fail fast iterators
++     */
++    private transient Set<E> uniqueSet;
++
++    /**
++     * Constructor needed for subclass serialisation.
++     */
++    protected AbstractMapBag() {
++        super();
++    }
++
++    /**
++     * Constructor that assigns the specified Map as the backing store.
++     * The map must be empty and non-null.
++     *
++     * @param map the map to assign
++     */
++    protected AbstractMapBag(Map<E, MutableInteger> map) {
++        super();
++        this.map = map;
++    }
++
++    /**
++     * Utility method for implementations to access the map that backs
++     * this bag. Not intended for interactive use outside of subclasses.
++     *
++     * @return the map being used by the Bag
++     */
++    protected Map<E, MutableInteger> getMap() {
++        return map;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns the number of elements in this bag.
++     *
++     * @return current size of the bag
++     */
++    public int size() {
++        return size;
++    }
++
++    /**
++     * Returns true if the underlying map is empty.
++     *
++     * @return true if bag is empty
++     */
++    public boolean isEmpty() {
++        return map.isEmpty();
++    }
++
++    /**
++     * Returns the number of occurrence of the given element in this bag
++     * by looking up its count in the underlying map.
++     *
++     * @param object the object to search for
++     * @return the number of occurrences of the object, zero if not found
++     */
++    public int getCount(E object) {
++        MutableInteger count = map.get(object);
++        if (count != null) {
++            return count.value;
++        }
++        return 0;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Determines if the bag contains the given element by checking if the
++     * underlying map contains the element as a key.
++     *
++     * @param object the object to search for
++     * @return true if the bag contains the given element
++     */
++    public boolean contains(Object object) {
++        return map.containsKey(object);
++    }
++
++    /**
++     * Determines if the bag contains the given elements.
++     *
++     * @param coll the collection to check against
++     * @return <code>true</code> if the Bag contains all the collection
++     */
++    public boolean containsAll(Collection<?> coll) {
++        if (coll instanceof Bag) {
++            return containsAll((Bag<E>) coll);
++        }
++        return containsAll(new HashBag(coll));
++    }
++
++    /**
++     * Returns <code>true</code> if the bag contains all elements in
++     * the given collection, respecting cardinality.
++     *
++     * @param other the bag to check against
++     * @return <code>true</code> if the Bag contains all the collection
++     */
++    boolean containsAll(Bag<E> other) {
++        boolean result = true;
++        Iterator<E> it = other.uniqueSet().iterator();
++        while (it.hasNext()) {
++            E current = it.next();
++            boolean contains = getCount(current) >= other.getCount(current);
++            result = result && contains;
++        }
++        return result;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator over the bag elements.
++     * Elements present in the Bag more than once will be returned repeatedly.
++     *
++     * @return the iterator
++     */
++    public Iterator<E> iterator() {
++        return new BagIterator<E>(this);
++    }
++
++    /**
++     * Inner class iterator for the Bag.
++     */
++    static class BagIterator <E> implements Iterator<E> {
++        private AbstractMapBag<E> parent;
++        private Iterator<Map.Entry<E, MutableInteger>> entryIterator;
++        private Map.Entry<E, MutableInteger> current;
++        private int itemCount;
++        private final int mods;
++        private boolean canRemove;
++
++        /**
++         * Constructor.
++         *
++         * @param parent the parent bag
++         */
++        public BagIterator(AbstractMapBag<E> parent) {
++            this.parent = parent;
++            this.entryIterator = parent.map.entrySet().iterator();
++            this.current = null;
++            this.mods = parent.modCount;
++            this.canRemove = false;
++        }
++
++        public boolean hasNext() {
++            return (itemCount > 0 || entryIterator.hasNext());
++        }
++
++        public E next() {
++            if (parent.modCount != mods) {
++                throw new ConcurrentModificationException();
++            }
++            if (itemCount == 0) {
++                current = entryIterator.next();
++                itemCount = current.getValue().value;
++            }
++            canRemove = true;
++            itemCount--;
++            return current.getKey();
++        }
++
++        public void remove() {
++            if (parent.modCount != mods) {
++                throw new ConcurrentModificationException();
++            }
++            if (canRemove == false) {
++                throw new IllegalStateException();
++            }
++            MutableInteger mut = current.getValue();
++            if (mut.value > 0) {
++                mut.value--;
++                parent.size--;
++            } else {
++                entryIterator.remove();
++            }
++            canRemove = false;
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Adds a new element to the bag, incrementing its count in the underlying map.
++     *
++     * @param object the object to add
++     * @return <code>true</code> if the object was not already in the <code>uniqueSet</code>
++     */
++    public boolean add(E object) {
++        return add(object, 1);
++    }
++
++    /**
++     * Adds a new element to the bag, incrementing its count in the map.
++     *
++     * @param object  the object to search for
++     * @param nCopies the number of copies to add
++     * @return <code>true</code> if the object was not already in the <code>uniqueSet</code>
++     */
++    public boolean add(E object, int nCopies) {
++        modCount++;
++        if (nCopies > 0) {
++            MutableInteger mut = map.get(object);
++            size += nCopies;
++            if (mut == null) {
++                map.put(object, new MutableInteger(nCopies));
++                return true;
++            } else {
++                mut.value += nCopies;
++                return false;
++            }
++        } else {
++            return false;
++        }
++    }
++
++    /**
++     * Invokes {@link #add(Object)} for each element in the given collection.
++     *
++     * @param coll the collection to add
++     * @return <code>true</code> if this call changed the bag
++     */
++    public boolean addAll(Collection<? extends E> coll) {
++        boolean changed = false;
++        Iterator<? extends E> i = coll.iterator();
++        while (i.hasNext()) {
++            boolean added = add(i.next());
++            changed = changed || added;
++        }
++        return changed;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Clears the bag by clearing the underlying map.
++     */
++    public void clear() {
++        modCount++;
++        map.clear();
++        size = 0;
++    }
++
++    /**
++     * Removes all copies of the specified object from the bag.
++     *
++     * @param object the object to remove
++     * @return true if the bag changed
++     */
++    public boolean remove(Object object) {
++        MutableInteger mut = map.get(object);
++        if (mut == null) {
++            return false;
++        }
++        modCount++;
++        map.remove(object);
++        size -= mut.value;
++        return true;
++    }
++
++    /**
++     * Removes a specified number of copies of an object from the bag.
++     *
++     * @param object  the object to remove
++     * @param nCopies the number of copies to remove
++     * @return true if the bag changed
++     */
++    public boolean remove(E object, int nCopies) {
++        MutableInteger mut = map.get(object);
++        if (mut == null) {
++            return false;
++        }
++        if (nCopies <= 0) {
++            return false;
++        }
++        modCount++;
++        if (nCopies < mut.value) {
++            mut.value -= nCopies;
++            map.put(object, mut);
++            size -= nCopies;
++        } else {
++            map.remove(object);
++            size -= mut.value;
++        }
++        return true;
++    }
++
++    /**
++     * Removes objects from the bag according to their count in the specified collection.
++     *
++     * @param coll the collection to use
++     * @return true if the bag changed
++     */
++    public boolean removeAll(Collection<?> coll) {
++        boolean result = false;
++        if (coll != null) {
++            Iterator i = coll.iterator();
++            while (i.hasNext()) {
++                boolean changed = remove((E) i.next(), 1);
++                result = result || changed;
++            }
++        }
++        return result;
++    }
++
++    /**
++     * Remove any members of the bag that are not in the given
++     * bag, respecting cardinality.
++     *
++     * @param coll the collection to retain
++     * @return true if this call changed the collection
++     */
++    public boolean retainAll(Collection<?> coll) {
++        if (coll instanceof Bag) {
++            return retainAll((Bag<? extends E>) coll);
++        }
++        return retainAll(new HashBag(coll));
++    }
++
++    /**
++     * Remove any members of the bag that are not in the given
++     * bag, respecting cardinality.
++     *
++     * @param other the bag to retain
++     * @return <code>true</code> if this call changed the collection
++     * @see #retainAll(Collection)
++     */
++    boolean retainAll(Bag<E> other) {
++        boolean result = false;
++        Bag excess = new HashBag();
++        Iterator<E> i = uniqueSet().iterator();
++        while (i.hasNext()) {
++            E current = i.next();
++            int myCount = getCount(current);
++            int otherCount = other.getCount(current);
++            if (1 <= otherCount && otherCount <= myCount) {
++                excess.add(current, myCount - otherCount);
++            } else {
++                excess.add(current, myCount);
++            }
++        }
++        if (!excess.isEmpty()) {
++            result = removeAll(excess);
++        }
++        return result;
++    }
++
++    //-----------------------------------------------------------------------
++
++    /**
++     * Mutable integer class for storing the data.
++     */
++    protected static class MutableInteger {
++        /**
++         * The value of this mutable.
++         */
++        protected int value;
++
++        /**
++         * Constructor.
++         *
++         * @param value the initial value
++         */
++        MutableInteger(int value) {
++            this.value = value;
++        }
++
++        public boolean equals(Object obj) {
++            if (obj instanceof MutableInteger == false) {
++                return false;
++            }
++            return ((MutableInteger) obj).value == value;
++        }
++
++        public int hashCode() {
++            return value;
++        }
++    }
++
++    /**
++     * Returns an array of all of this bag's elements.
++     *
++     * @return an array of all of this bag's elements
++     */
++    public Object[] toArray() {
++        Object[] result = new Object[size()];
++        int i = 0;
++        Iterator<E> it = map.keySet().iterator();
++        while (it.hasNext()) {
++            E current = it.next();
++            for (int index = getCount(current); index > 0; index--) {
++                result[i++] = current;
++            }
++        }
++        return result;
++    }
++
++    /**
++     * Returns an array of all of this bag's elements.
++     *
++     * @param array the array to populate
++     * @return an array of all of this bag's elements
++     */
++    public Object[] toArray(Object[] array) {
++        int size = size();
++        if (array.length < size) {
++            array = (Object[]) Array.newInstance(array.getClass().getComponentType(), size);
++        }
++
++        int i = 0;
++        Iterator<E> it = map.keySet().iterator();
++        while (it.hasNext()) {
++            E current = it.next();
++            for (int index = getCount(current); index > 0; index--) {
++                array[i++] = current;
++            }
++        }
++        if (array.length > size) {
++            array[size] = null;
++        }
++        return array;
++    }
++
++    /**
++     * Returns an unmodifiable view of the underlying map's key set.
++     *
++     * @return the set of unique elements in this bag
++     */
++    public Set<E> uniqueSet() {
++        if (uniqueSet == null) {
++            uniqueSet = UnmodifiableSet.decorate(map.keySet());
++        }
++        return uniqueSet;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     */
++    protected void doWriteObject(ObjectOutputStream out) throws IOException {
++        out.writeInt(map.size());
++        for (Iterator<Map.Entry<E, MutableInteger>> it = map.entrySet().iterator(); it.hasNext();) {
++            Map.Entry<E, MutableInteger> entry = it.next();
++            out.writeObject(entry.getKey());
++            out.writeInt(entry.getValue().value);
++        }
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     *
++     * @param map the map to use
++     * @param in  the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     */
++    protected void doReadObject(Map<E, MutableInteger> map, ObjectInputStream in) throws IOException, ClassNotFoundException {
++        this.map = map;
++        int entrySize = in.readInt();
++        for (int i = 0; i < entrySize; i++) {
++            E obj = (E) in.readObject();
++            int count = in.readInt();
++            map.put(obj, new MutableInteger(count));
++            size += count;
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Compares this Bag to another.
++     * This Bag equals another Bag if it contains the same number of occurrences of
++     * the same elements.
++     *
++     * @param object the Bag to compare to
++     * @return true if equal
++     */
++    public boolean equals(Object object) {
++        if (object == this) {
++            return true;
++        }
++        if (object instanceof Bag == false) {
++            return false;
++        }
++        Bag other = (Bag) object;
++        if (other.size() != size()) {
++            return false;
++        }
++        for (Iterator<E> it = map.keySet().iterator(); it.hasNext();) {
++            E element = it.next();
++            if (other.getCount(element) != getCount(element)) {
++                return false;
++            }
++        }
++        return true;
++    }
++
++    /**
++     * Gets a hash code for the Bag compatible with the definition of equals.
++     * The hash code is defined as the sum total of a hash code for each element.
++     * The per element hash code is defined as
++     * <code>(e==null ? 0 : e.hashCode()) ^ noOccurances)</code>.
++     * This hash code is compatible with the Set interface.
++     *
++     * @return the hash code of the Bag
++     */
++    public int hashCode() {
++        int total = 0;
++        for (Iterator<Map.Entry<E, MutableInteger>> it = map.entrySet().iterator(); it.hasNext();) {
++            Map.Entry<E, MutableInteger> entry = it.next();
++            Object element = entry.getKey();
++            Integer count = entry.getValue().value;
++            total += (element == null ? 0 : element.hashCode()) ^ count;
++        }
++        return total;
++    }
++
++    /**
++     * Implement a toString() method suitable for debugging.
++     *
++     * @return a debugging toString
++     */
++    public String toString() {
++        if (size() == 0) {
++            return "[]";
++        }
++        StringBuffer buf = new StringBuffer();
++        buf.append('[');
++        Iterator<E> it = uniqueSet().iterator();
++        while (it.hasNext()) {
++            E current = it.next();
++            int count = getCount(current);
++            buf.append(count);
++            buf.append(':');
++            buf.append(current);
++            if (it.hasNext()) {
++                buf.append(',');
++            }
++        }
++        buf.append(']');
++        return buf.toString();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/AbstractSortedBagDecorator.java
+@@ -0,0 +1,75 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.SortedBag;
++
++import java.util.Comparator;
++
++/**
++ * Decorates another <code>SortedBag</code> to provide additional behaviour.
++ * <p/>
++ * Methods are forwarded directly to the decorated bag.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractSortedBagDecorator <E> extends AbstractBagDecorator<E> implements SortedBag<E> {
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     *
++     * @since Commons Collections 3.1
++     */
++    protected AbstractSortedBagDecorator() {
++        super();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param bag the bag to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    protected AbstractSortedBagDecorator(SortedBag<E> bag) {
++        super(bag);
++    }
++
++    /**
++     * Gets the bag being decorated.
++     *
++     * @return the decorated bag
++     */
++    protected SortedBag<E> getSortedBag() {
++        return (SortedBag<E>) getCollection();
++    }
++
++    //-----------------------------------------------------------------------
++    public E first() {
++        return getSortedBag().first();
++    }
++
++    public E last() {
++        return getSortedBag().last();
++    }
++
++    public Comparator<? super E> comparator() {
++        return getSortedBag().comparator();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/HashBag.java
+@@ -0,0 +1,84 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.Bag;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.HashMap;
++
++/**
++ * Implements <code>Bag</code>, using a <code>HashMap</code> to provide the
++ * data storage. This is the standard implementation of a bag.
++ * <p/>
++ * A <code>Bag</code> stores each object in the collection together with a
++ * count of occurrences. Extra methods on the interface allow multiple copies
++ * of an object to be added or removed at once. It is important to read the
++ * interface javadoc carefully as several methods violate the
++ * <code>Collection</code> interface specification.
++ *
++ * @author Chuck Burdick
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0 (previously in main package v2.0)
++ */
++public class HashBag <E> extends AbstractMapBag<E> implements Bag<E>, Serializable {
++
++    /**
++     * Serial version lock
++     */
++    static final long serialVersionUID = -6561115435802554013L;
++
++    /**
++     * Constructs an empty <code>HashBag</code>.
++     */
++    public HashBag() {
++        super(new HashMap<E, MutableInteger>());
++    }
++
++    /**
++     * Constructs a bag containing all the members of the given collection.
++     *
++     * @param coll a collection to copy into this bag
++     */
++    public HashBag(Collection<? extends E> coll) {
++        this();
++        addAll(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the bag out using a custom routine.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        super.doWriteObject(out);
++    }
++
++    /**
++     * Read the bag in using a custom routine.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        super.doReadObject(new HashMap<E, MutableInteger>(), in);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/PredicatedBag.java
+@@ -0,0 +1,109 @@
++// GenericsNotes: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.Bag;
++import org.apache.commons.collections15.Predicate;
++import org.apache.commons.collections15.collection.PredicatedCollection;
++
++import java.util.Set;
++
++/**
++ * Decorates another <code>Bag</code> to validate that additions
++ * match a specified predicate.
++ * <p/>
++ * This bag exists to provide validation for the decorated bag.
++ * It is normally created to decorate an empty bag.
++ * If an object cannot be added to the bag, an IllegalArgumentException is thrown.
++ * <p/>
++ * One usage would be to ensure that no null entries are added to the bag.
++ * <pre>Bag bag = PredicatedBag.decorate(new HashBag(), NotNullPredicate.INSTANCE);</pre>
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class PredicatedBag <E> extends PredicatedCollection<E> implements Bag<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -2575833140344736876L;
++
++    /**
++     * Factory method to create a predicated (validating) bag.
++     * <p/>
++     * If there are any elements already in the bag being decorated, they
++     * are validated.
++     *
++     * @param bag       the bag to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @return a new predicated Bag
++     * @throws IllegalArgumentException if bag or predicate is null
++     * @throws IllegalArgumentException if the bag contains invalid elements
++     */
++    public static <E> Bag<E> decorate(Bag<E> bag, Predicate<? super E> predicate) {
++        return new PredicatedBag<E>(bag, predicate);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the bag being decorated, they
++     * are validated.
++     *
++     * @param bag       the bag to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @throws IllegalArgumentException if bag or predicate is null
++     * @throws IllegalArgumentException if the bag contains invalid elements
++     */
++    protected PredicatedBag(Bag<E> bag, Predicate<? super E> predicate) {
++        super(bag, predicate);
++    }
++
++    /**
++     * Gets the decorated bag.
++     *
++     * @return the decorated bag
++     */
++    protected Bag<E> getBag() {
++        return (Bag<E>) getCollection();
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(E object, int count) {
++        validate(object);
++        return getBag().add(object, count);
++    }
++
++    public boolean remove(E object, int count) {
++        return getBag().remove(object, count);
++    }
++
++    public Set uniqueSet() {
++        return getBag().uniqueSet();
++    }
++
++    public int getCount(E object) {
++        return getBag().getCount(object);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/PredicatedSortedBag.java
+@@ -0,0 +1,103 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.Predicate;
++import org.apache.commons.collections15.SortedBag;
++
++import java.util.Comparator;
++
++/**
++ * Decorates another <code>SortedBag</code> to validate that additions
++ * match a specified predicate.
++ * <p/>
++ * This bag exists to provide validation for the decorated bag.
++ * It is normally created to decorate an empty bag.
++ * If an object cannot be added to the bag, an IllegalArgumentException is thrown.
++ * <p/>
++ * One usage would be to ensure that no null entries are added to the bag.
++ * <pre>SortedBag bag = PredicatedSortedBag.decorate(new TreeBag(), NotNullPredicate.INSTANCE);</pre>
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class PredicatedSortedBag <E> extends PredicatedBag<E> implements SortedBag<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 3448581314086406616L;
++
++    /**
++     * Factory method to create a predicated (validating) bag.
++     * <p/>
++     * If there are any elements already in the bag being decorated, they
++     * are validated.
++     *
++     * @param bag       the bag to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @return a new predicated SortedBag
++     * @throws IllegalArgumentException if bag or predicate is null
++     * @throws IllegalArgumentException if the bag contains invalid elements
++     */
++    public static <E> SortedBag<E> decorate(SortedBag<E> bag, Predicate<? super E> predicate) {
++        return new PredicatedSortedBag(bag, predicate);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the bag being decorated, they
++     * are validated.
++     *
++     * @param bag       the bag to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @throws IllegalArgumentException if bag or predicate is null
++     * @throws IllegalArgumentException if the bag contains invalid elements
++     */
++    protected PredicatedSortedBag(SortedBag<E> bag, Predicate<? super E> predicate) {
++        super(bag, predicate);
++    }
++
++    /**
++     * Gets the decorated sorted bag.
++     *
++     * @return the decorated bag
++     */
++    protected SortedBag<E> getSortedBag() {
++        return (SortedBag<E>) getCollection();
++    }
++
++    //-----------------------------------------------------------------------
++    public E first() {
++        return getSortedBag().first();
++    }
++
++    public E last() {
++        return getSortedBag().last();
++    }
++
++    public Comparator<? super E> comparator() {
++        return getSortedBag().comparator();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/SynchronizedBag.java
+@@ -0,0 +1,129 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.Bag;
++import org.apache.commons.collections15.collection.SynchronizedCollection;
++import org.apache.commons.collections15.set.SynchronizedSet;
++
++import java.util.Set;
++
++/**
++ * Decorates another <code>Bag</code> to synchronize its behaviour
++ * for a multi-threaded environment.
++ * <p/>
++ * Methods are synchronized, then forwarded to the decorated bag.
++ * Iterators must be separately synchronized around the loop.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class SynchronizedBag <E> extends SynchronizedCollection<E> implements Bag<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 8084674570753837109L;
++
++    /**
++     * Factory method to create a synchronized bag.
++     *
++     * @param bag the bag to decorate, must not be null
++     * @return a new synchronized Bag
++     * @throws IllegalArgumentException if bag is null
++     */
++    public static <E> Bag<E> decorate(Bag<E> bag) {
++        return new SynchronizedBag<E>(bag);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param bag the bag to decorate, must not be null
++     * @throws IllegalArgumentException if bag is null
++     */
++    protected SynchronizedBag(Bag<E> bag) {
++        super(bag);
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param bag  the bag to decorate, must not be null
++     * @param lock the lock to use, must not be null
++     * @throws IllegalArgumentException if bag is null
++     */
++    protected SynchronizedBag(Bag<E> bag, Object lock) {
++        super(bag, lock);
++    }
++
++    /**
++     * Gets the bag being decorated.
++     *
++     * @return the decorated bag
++     */
++    protected Bag<E> getBag() {
++        return (Bag<E>) collection;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(E object, int count) {
++        synchronized (lock) {
++            return getBag().add(object, count);
++        }
++    }
++
++    public boolean remove(E object, int count) {
++        synchronized (lock) {
++            return getBag().remove(object, count);
++        }
++    }
++
++    public Set<E> uniqueSet() {
++        synchronized (lock) {
++            Set<E> set = getBag().uniqueSet();
++            return new SynchronizedBagSet(set, lock);
++        }
++    }
++
++    public int getCount(E object) {
++        synchronized (lock) {
++            return getBag().getCount(object);
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Synchronized Set for the Bag class.
++     */
++    class SynchronizedBagSet extends SynchronizedSet<E> {
++        /**
++         * Constructor.
++         *
++         * @param set  the set to decorate
++         * @param lock the lock to use, shared with the bag
++         */
++        SynchronizedBagSet(Set<E> set, Object lock) {
++            super(set, lock);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/SynchronizedSortedBag.java
+@@ -0,0 +1,105 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.Bag;
++import org.apache.commons.collections15.SortedBag;
++
++import java.util.Comparator;
++
++/**
++ * Decorates another <code>SortedBag</code> to synchronize its behaviour
++ * for a multi-threaded environment.
++ * <p/>
++ * Methods are synchronized, then forwarded to the decorated bag.
++ * Iterators must be separately synchronized around the loop.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class SynchronizedSortedBag <E> extends SynchronizedBag<E> implements SortedBag<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 722374056718497858L;
++
++    /**
++     * Factory method to create a synchronized sorted bag.
++     *
++     * @param bag the bag to decorate, must not be null
++     * @return a new synchronized SortedBag
++     * @throws IllegalArgumentException if bag is null
++     */
++    public static <E> SortedBag<E> decorate(SortedBag<E> bag) {
++        return new SynchronizedSortedBag<E>(bag);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param bag the bag to decorate, must not be null
++     * @throws IllegalArgumentException if bag is null
++     */
++    protected SynchronizedSortedBag(SortedBag<E> bag) {
++        super(bag);
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param bag  the bag to decorate, must not be null
++     * @param lock the lock to use, must not be null
++     * @throws IllegalArgumentException if bag is null
++     */
++    protected SynchronizedSortedBag(Bag<E> bag, Object lock) {
++        super(bag, lock);
++    }
++
++    /**
++     * Gets the bag being decorated.
++     *
++     * @return the decorated bag
++     */
++    protected SortedBag<E> getSortedBag() {
++        return (SortedBag<E>) collection;
++    }
++
++    //-----------------------------------------------------------------------
++    public synchronized E first() {
++        synchronized (lock) {
++            return getSortedBag().first();
++        }
++    }
++
++    public synchronized E last() {
++        synchronized (lock) {
++            return getSortedBag().last();
++        }
++    }
++
++    public synchronized Comparator<? super E> comparator() {
++        synchronized (lock) {
++            return getSortedBag().comparator();
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/TransformedBag.java
+@@ -0,0 +1,108 @@
++// TODO: Not yet converted - deprecated (by me).
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.Bag;
++import org.apache.commons.collections15.Transformer;
++import org.apache.commons.collections15.collection.TransformedCollection;
++import org.apache.commons.collections15.set.TransformedSet;
++
++import java.util.Set;
++
++/**
++ * Decorates another <code>Bag</code> to transform objects that are added.
++ * <p/>
++ * The add methods are affected by this class.
++ * Thus objects must be removed or searched for using their transformed form.
++ * For example, if the transformation converts Strings to Integers, you must
++ * use the Integer form to remove objects.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ * <p>
++ * Note: This class cannot support generics without breaking the Collection contract.
++ *
++ * @author Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class TransformedBag extends TransformedCollection implements Bag {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 5421170911299074185L;
++
++    /**
++     * Factory method to create a transforming bag.
++     * <p/>
++     * If there are any elements already in the bag being decorated, they
++     * are NOT transformed.
++     *
++     * @param bag         the bag to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @return a new transformed Bag
++     * @throws IllegalArgumentException if bag or transformer is null
++     */
++    public static <I,O> Bag<O> decorate(Bag<I> bag, Transformer<? super I, ? extends O> transformer) {
++        return new TransformedBag(bag, transformer);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the bag being decorated, they
++     * are NOT transformed.
++     *
++     * @param bag         the bag to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @throws IllegalArgumentException if bag or transformer is null
++     */
++    protected TransformedBag(Bag bag, Transformer transformer) {
++        super(bag, transformer);
++    }
++
++    /**
++     * Gets the decorated bag.
++     *
++     * @return the decorated bag
++     */
++    protected Bag getBag() {
++        return (Bag) collection;
++    }
++
++    //-----------------------------------------------------------------------
++    public int getCount(Object object) {
++        return getBag().getCount(object);
++    }
++
++    public boolean remove(Object object, int nCopies) {
++        return getBag().remove(object, nCopies);
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(Object object, int nCopies) {
++        object = transform(object);
++        return getBag().add(object, nCopies);
++    }
++
++    public Set uniqueSet() {
++        Set set = getBag().uniqueSet();
++        return TransformedSet.decorate(set, transformer);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/TransformedSortedBag.java
+@@ -0,0 +1,99 @@
++// TODO: Not yet converted - deprecated (by me).
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.SortedBag;
++import org.apache.commons.collections15.Transformer;
++
++import java.util.Comparator;
++
++/**
++ * Decorates another <code>SortedBag</code> to transform objects that are added.
++ * <p/>
++ * The add methods are affected by this class.
++ * Thus objects must be removed or searched for using their transformed form.
++ * For example, if the transformation converts Strings to Integers, you must
++ * use the Integer form to remove objects.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ * <p>
++ * Note: This class cannot support generics without breaking the Collection contract.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class TransformedSortedBag extends TransformedBag implements SortedBag {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -251737742649401930L;
++
++    /**
++     * Factory method to create a transforming sorted bag.
++     * <p/>
++     * If there are any elements already in the bag being decorated, they
++     * are NOT transformed.
++     *
++     * @param bag         the bag to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @return a new transformed SortedBag
++     * @throws IllegalArgumentException if bag or transformer is null
++     */
++    public static <I,O> SortedBag<O> decorate(SortedBag<I> bag, Transformer<? super I, ? extends O> transformer) {
++        return new TransformedSortedBag(bag, transformer);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the bag being decorated, they
++     * are NOT transformed.
++     *
++     * @param bag         the bag to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @throws IllegalArgumentException if bag or transformer is null
++     */
++    protected TransformedSortedBag(SortedBag bag, Transformer transformer) {
++        super(bag, transformer);
++    }
++
++    /**
++     * Gets the decorated bag.
++     *
++     * @return the decorated bag
++     */
++    protected SortedBag getSortedBag() {
++        return (SortedBag) collection;
++    }
++
++    //-----------------------------------------------------------------------
++    public Object first() {
++        return getSortedBag().first();
++    }
++
++    public Object last() {
++        return getSortedBag().last();
++    }
++
++    public Comparator comparator() {
++        return getSortedBag().comparator();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/TreeBag.java
+@@ -0,0 +1,115 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.SortedBag;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Comparator;
++import java.util.SortedMap;
++import java.util.TreeMap;
++
++/**
++ * Implements <code>SortedBag</code>, using a <code>TreeMap</code> to provide
++ * the data storage. This is the standard implementation of a sorted bag.
++ * <p/>
++ * Order will be maintained among the bag members and can be viewed through the
++ * iterator.
++ * <p/>
++ * A <code>Bag</code> stores each object in the collection together with a
++ * count of occurrences. Extra methods on the interface allow multiple copies
++ * of an object to be added or removed at once. It is important to read the
++ * interface javadoc carefully as several methods violate the
++ * <code>Collection</code> interface specification.
++ *
++ * @author Matt Hall, John Watkinson, Chuck Burdick
++ * @author Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0 (previously in main package v2.0)
++ */
++public class TreeBag <E> extends AbstractMapBag<E> implements SortedBag<E>, Serializable {
++
++    /**
++     * Serial version lock
++     */
++    static final long serialVersionUID = -7740146511091606676L;
++
++    /**
++     * Constructs an empty <code>TreeBag</code>.
++     */
++    public TreeBag() {
++        super(new TreeMap<E, MutableInteger>());
++    }
++
++    /**
++     * Constructs an empty bag that maintains order on its unique
++     * representative members according to the given {@link Comparator}.
++     *
++     * @param comparator the comparator to use
++     */
++    public TreeBag(Comparator<? super E> comparator) {
++        super(new TreeMap<E, MutableInteger>(comparator));
++    }
++
++    /**
++     * Constructs a <code>TreeBag</code> containing all the members of the
++     * specified collection.
++     *
++     * @param coll the collection to copy into the bag
++     */
++    public TreeBag(Collection<? extends E> coll) {
++        this();
++        addAll(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    public E first() {
++        return ((SortedMap<E, MutableInteger>) getMap()).firstKey();
++    }
++
++    public E last() {
++        return ((SortedMap<E, MutableInteger>) getMap()).lastKey();
++    }
++
++    public Comparator comparator() {
++        return ((SortedMap) getMap()).comparator();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the bag out using a custom routine.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(comparator());
++        super.doWriteObject(out);
++    }
++
++    /**
++     * Read the bag in using a custom routine.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        Comparator comp = (Comparator) in.readObject();
++        super.doReadObject(new TreeMap<E, MutableInteger>(comp), in);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/TypedBag.java
+@@ -0,0 +1,61 @@
++// GenericsNote: Deprecated and not coverted, type safety not necessary anymore.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.Bag;
++import org.apache.commons.collections15.functors.InstanceofPredicate;
++
++/**
++ * Decorates another <code>Bag</code> to validate that elements added
++ * are of a specific type.
++ * <p/>
++ * The validation of additions is performed via an instanceof test against
++ * a specified <code>Class</code>. If an object cannot be added to the
++ * collection, an IllegalArgumentException is thrown.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ * @deprecated Type safety classes not required anymore under 1.5, just use a typed Bag.
++ */
++public class TypedBag {
++
++    /**
++     * Factory method to create a typed bag.
++     * <p/>
++     * If there are any elements already in the bag being decorated, they
++     * are validated.
++     *
++     * @param bag  the bag to decorate, must not be null
++     * @param type the type to allow into the bag, must not be null
++     * @return a new typed Bag
++     * @throws IllegalArgumentException if bag or type is null
++     * @throws IllegalArgumentException if the bag contains invalid elements
++     */
++    public static Bag decorate(Bag bag, Class type) {
++        return new PredicatedBag(bag, InstanceofPredicate.getInstance(type));
++    }
++
++    /**
++     * Restrictive constructor.
++     */
++    protected TypedBag() {
++        super();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/TypedSortedBag.java
+@@ -0,0 +1,60 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.SortedBag;
++import org.apache.commons.collections15.functors.InstanceofPredicate;
++
++/**
++ * Decorates another <code>SortedBag</code> to validate that elements added
++ * are of a specific type.
++ * <p/>
++ * The validation of additions is performed via an instanceof test against
++ * a specified <code>Class</code>. If an object cannot be added to the
++ * collection, an IllegalArgumentException is thrown.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public class TypedSortedBag <E> {
++
++    /**
++     * Factory method to create a typed sorted bag.
++     * <p/>
++     * If there are any elements already in the bag being decorated, they
++     * are validated.
++     *
++     * @param bag  the bag to decorate, must not be null
++     * @param type the type to allow into the bag, must not be null
++     * @return a new transformed SortedBag
++     * @throws IllegalArgumentException if bag or type is null
++     * @throws IllegalArgumentException if the bag contains invalid elements
++     */
++    public static <E> SortedBag<E> decorate(SortedBag<E> bag, Class<E> type) {
++        return new PredicatedSortedBag<E>(bag, InstanceofPredicate.getInstance(type));
++    }
++
++    /**
++     * Restrictive constructor.
++     */
++    protected TypedSortedBag() {
++        super();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/UnmodifiableBag.java
+@@ -0,0 +1,142 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.Bag;
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.iterators.UnmodifiableIterator;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Set;
++
++/**
++ * Decorates another <code>Bag</code> to ensure it can't be altered.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableBag <E> extends AbstractBagDecorator<E> implements Unmodifiable, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -1873799975157099624L;
++
++    /**
++     * Factory method to create an unmodifiable bag.
++     * <p/>
++     * If the bag passed in is already unmodifiable, it is returned.
++     *
++     * @param bag the bag to decorate, must not be null
++     * @return an unmodifiable Bag
++     * @throws IllegalArgumentException if bag is null
++     */
++    public static <E> Bag<E> decorate(Bag<E> bag) {
++        if (bag instanceof Unmodifiable) {
++            return bag;
++        }
++        return new UnmodifiableBag<E>(bag);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param bag the bag to decorate, must not be null
++     * @throws IllegalArgumentException if bag is null
++     */
++    private UnmodifiableBag(Bag<E> bag) {
++        super(bag);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the collection out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(collection);
++    }
++
++    /**
++     * Read the collection in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        collection = (Collection<E>) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    public Iterator<E> iterator() {
++        return UnmodifiableIterator.decorate(getCollection().iterator());
++    }
++
++    public boolean add(E object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean remove(Object object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(E object, int count) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean remove(E object, int count) {
++        throw new UnsupportedOperationException();
++    }
++
++    public Set<E> uniqueSet() {
++        Set<E> set = getBag().uniqueSet();
++        return UnmodifiableSet.decorate(set);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/UnmodifiableSortedBag.java
+@@ -0,0 +1,142 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bag;
++
++import org.apache.commons.collections15.SortedBag;
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.iterators.UnmodifiableIterator;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Set;
++
++/**
++ * Decorates another <code>SortedBag</code> to ensure it can't be altered.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableSortedBag <E> extends AbstractSortedBagDecorator<E> implements Unmodifiable, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -3190437252665717841L;
++
++    /**
++     * Factory method to create an unmodifiable bag.
++     * <p/>
++     * If the bag passed in is already unmodifiable, it is returned.
++     *
++     * @param bag the bag to decorate, must not be null
++     * @return an unmodifiable SortedBag
++     * @throws IllegalArgumentException if bag is null
++     */
++    public static <E> SortedBag<E> decorate(SortedBag<E> bag) {
++        if (bag instanceof Unmodifiable) {
++            return bag;
++        }
++        return new UnmodifiableSortedBag<E>(bag);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param bag the bag to decorate, must not be null
++     * @throws IllegalArgumentException if bag is null
++     */
++    private UnmodifiableSortedBag(SortedBag<E> bag) {
++        super(bag);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the collection out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(collection);
++    }
++
++    /**
++     * Read the collection in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        collection = (Collection<E>) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    public Iterator iterator() {
++        return UnmodifiableIterator.decorate(getCollection().iterator());
++    }
++
++    public boolean add(E object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean remove(Object object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(E object, int count) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean remove(E object, int count) {
++        throw new UnsupportedOperationException();
++    }
++
++    public Set<E> uniqueSet() {
++        Set<E> set = getBag().uniqueSet();
++        return UnmodifiableSet.decorate(set);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bag/package.html
+@@ -0,0 +1,39 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:19 pents90 Exp $ -->
++ <!--
++   Copyright 2003-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<BODY>
++<p>
++This package contains implementations of the
++{@link org.apache.commons.collections.Bag Bag} and 
++{@link org.apache.commons.collections.SortedBag SortedBag} interfaces.
++A bag stores an object and a count of the number of occurences of the object.
++<p>
++The following implementations are provided in the package:
++<ul>
++<li>HashBag - implementation that uses a HashMap to store the data
++<li>TreeBag - implementation that uses a TreeMap to store the data
++</ul>
++<p>
++The following decorators are provided in the package:
++<ul>
++<li>Synchronized - synchronizes method access for multi-threaded environments
++<li>Unmodifiable - ensures the bag cannot be altered
++<li>Predicated - ensures that only elements that are valid according to a predicate can be added
++<li>Typed - ensures that only elements that are of a specific type can be added
++<li>Transformed - transforms each element added to the bag
++</ul>
++</pre>
++</BODY>
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bidimap/AbstractBidiMapDecorator.java
+@@ -0,0 +1,82 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bidimap;
++
++import org.apache.commons.collections15.BidiMap;
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.map.AbstractMapDecorator;
++
++import java.util.Set;
++
++/**
++ * Provides a base decorator that enables additional functionality to be added
++ * to a BidiMap via decoration.
++ * <p/>
++ * Methods are forwarded directly to the decorated map.
++ * <p/>
++ * This implementation does not perform any special processing with the map views.
++ * Instead it simply returns the set/collection from the wrapped map. This may be
++ * undesirable, for example if you are trying to write a validating implementation
++ * it would provide a loophole around the validation.
++ * But, you might want that loophole, so this class is kept simple.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractBidiMapDecorator <K,V> extends AbstractMapDecorator<K, V> implements BidiMap<K, V> {
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    protected AbstractBidiMapDecorator(BidiMap<K, V> map) {
++        super(map);
++    }
++
++    /**
++     * Gets the map being decorated.
++     *
++     * @return the decorated map
++     */
++    protected BidiMap<K, V> getBidiMap() {
++        return (BidiMap<K, V>) map;
++    }
++
++    //-----------------------------------------------------------------------
++    public MapIterator<K, V> mapIterator() {
++        return getBidiMap().mapIterator();
++    }
++
++    public K getKey(Object value) {
++        return getBidiMap().getKey(value);
++    }
++
++    public K removeValue(Object value) {
++        return getBidiMap().removeValue(value);
++    }
++
++    public BidiMap<V, K> inverseBidiMap() {
++        return getBidiMap().inverseBidiMap();
++    }
++
++    public Set<V> values() {
++        return getBidiMap().values();
++    }
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bidimap/AbstractDualBidiMap.java
+@@ -0,0 +1,762 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bidimap;
++
++import org.apache.commons.collections15.BidiMap;
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.ResettableIterator;
++import org.apache.commons.collections15.collection.AbstractCollectionDecorator;
++import org.apache.commons.collections15.iterators.AbstractIteratorDecorator;
++import org.apache.commons.collections15.keyvalue.AbstractMapEntryDecorator;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * Abstract <code>BidiMap</code> implemented using two maps.
++ * <p/>
++ * An implementation can be written simply by implementing the
++ * <code>createMap</code> method.
++ *
++ * @author Matthew Hawthorne
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Id: AbstractDualBidiMap.java,v 1.1 2005/10/11 17:05:19 pents90 Exp $
++ * @see DualHashBidiMap
++ * @see DualTreeBidiMap
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractDualBidiMap <K,V> implements BidiMap<K, V> {
++
++    /**
++     * Delegate maps.  The first map contains standard entries, and the
++     * second contains inverses.
++     */
++    protected transient Map<K, V> forwardMap;
++    protected transient Map<V, K> inverseMap;
++
++    /**
++     * Inverse view of this map.
++     */
++    protected transient BidiMap<V, K> inverseBidiMap = null;
++    /**
++     * View of the keys.
++     */
++    protected transient Set<K> keySet = null;
++    /**
++     * View of the values.
++     */
++    protected transient Set<V> values = null;
++    /**
++     * View of the entries.
++     */
++    protected transient Set<Map.Entry<K, V>> entrySet = null;
++
++    /**
++     * Creates an empty map, initialised by <code>createMap</code>.
++     * <p/>
++     * This constructor remains in place for deserialization.
++     * All other usage is deprecated in favour of
++     * {@link #AbstractDualBidiMap(Map, Map)}.
++     *
++     * @deprecated should not be used.
++     */
++    protected AbstractDualBidiMap() {
++        super();
++        forwardMap = createMap();
++        inverseMap = createMap();
++    }
++
++    /**
++     * Creates an empty map using the two maps specified as storage.
++     * <p/>
++     * The two maps must be a matching pair, normal and reverse.
++     * They will typically both be empty.
++     * <p/>
++     * Neither map is validated, so nulls may be passed in.
++     * If you choose to do this then the subclass constructor must populate
++     * the <code>maps[]</code> instance variable itself.
++     *
++     * @param normalMap  the normal direction map
++     * @param reverseMap the reverse direction map
++     * @since Commons Collections 3.1
++     */
++    protected AbstractDualBidiMap(Map<K, V> normalMap, Map<V, K> reverseMap) {
++        super();
++        forwardMap = normalMap;
++        inverseMap = reverseMap;
++    }
++
++    /**
++     * Constructs a map that decorates the specified maps,
++     * used by the subclass <code>createBidiMap</code> implementation.
++     *
++     * @param normalMap      the normal direction map
++     * @param reverseMap     the reverse direction map
++     * @param inverseBidiMap the inverse BidiMap
++     */
++    protected AbstractDualBidiMap(Map<K, V> normalMap, Map<V, K> reverseMap, BidiMap<V, K> inverseBidiMap) {
++        super();
++        forwardMap = normalMap;
++        inverseMap = reverseMap;
++        this.inverseBidiMap = inverseBidiMap;
++    }
++
++    /**
++     * Creates a new instance of the map used by the subclass to store data.
++     * <p/>
++     * This design is deeply flawed and has been deprecated.
++     * It relied on subclass data being used during a superclass constructor.
++     *
++     * @return the map to be used for internal storage
++     * @deprecated For constructors, use the new two map constructor.
++     *             For deserialization, populate the maps array directly in readObject.
++     */
++    protected Map createMap() {
++        return null;
++    }
++
++    /**
++     * Creates a new instance of the subclass.
++     *
++     * @param normalMap  the normal direction map
++     * @param reverseMap the reverse direction map
++     * @param inverseMap this map, which is the inverse in the new map
++     * @return the inverse map
++     */
++    protected abstract <K,V> BidiMap<K, V> createBidiMap(Map<K, V> normalMap, Map<V, K> reverseMap, BidiMap<V, K> inverseMap);
++
++    // Map delegation
++    //-----------------------------------------------------------------------
++    public V get(Object key) {
++        return forwardMap.get(key);
++    }
++
++    public int size() {
++        return forwardMap.size();
++    }
++
++    public boolean isEmpty() {
++        return forwardMap.isEmpty();
++    }
++
++    public boolean containsKey(Object key) {
++        return forwardMap.containsKey(key);
++    }
++
++    public boolean equals(Object obj) {
++        return forwardMap.equals(obj);
++    }
++
++    public int hashCode() {
++        return forwardMap.hashCode();
++    }
++
++    public String toString() {
++        return forwardMap.toString();
++    }
++
++    // BidiMap changes
++    //-----------------------------------------------------------------------
++    public V put(K key, V value) {
++        if (forwardMap.containsKey(key)) {
++            inverseMap.remove(forwardMap.get(key));
++        }
++        if (inverseMap.containsKey(value)) {
++            forwardMap.remove(inverseMap.get(value));
++        }
++        final V obj = forwardMap.put(key, value);
++        inverseMap.put(value, key);
++        return obj;
++    }
++
++    public void putAll(Map<? extends K, ? extends V> map) {
++        for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
++            Map.Entry entry = (Map.Entry) it.next();
++            put((K) entry.getKey(), (V) entry.getValue());
++        }
++    }
++
++    public V remove(Object key) {
++        V value = null;
++        if (forwardMap.containsKey(key)) {
++            value = forwardMap.remove(key);
++            inverseMap.remove(value);
++        }
++        return value;
++    }
++
++    public void clear() {
++        forwardMap.clear();
++        inverseMap.clear();
++    }
++
++    public boolean containsValue(Object value) {
++        return inverseMap.containsKey(value);
++    }
++
++    // BidiMap
++    //-----------------------------------------------------------------------
++    /**
++     * Obtains a <code>MapIterator</code> over the map.
++     * The iterator implements <code>ResetableMapIterator</code>.
++     * This implementation relies on the entrySet iterator.
++     * <p/>
++     * The setValue() methods only allow a new value to be set.
++     * If the value being set is already in the map, an IllegalArgumentException
++     * is thrown (as setValue cannot change the size of the map).
++     *
++     * @return a map iterator
++     */
++    public MapIterator<K, V> mapIterator() {
++        return new BidiMapIterator<K, V>(this);
++    }
++
++    public K getKey(Object value) {
++        return inverseMap.get(value);
++    }
++
++    public K removeValue(Object value) {
++        K key = null;
++        if (inverseMap.containsKey(value)) {
++            key = inverseMap.remove(value);
++            forwardMap.remove(key);
++        }
++        return key;
++    }
++
++    public BidiMap<V, K> inverseBidiMap() {
++        if (inverseBidiMap == null) {
++            inverseBidiMap = createBidiMap(inverseMap, forwardMap, this);
++        }
++        return inverseBidiMap;
++    }
++    
++    // Map views
++    //-----------------------------------------------------------------------
++    /**
++     * Gets a keySet view of the map.
++     * Changes made on the view are reflected in the map.
++     * The set supports remove and clear but not add.
++     *
++     * @return the keySet view
++     */
++    public Set<K> keySet() {
++        if (keySet == null) {
++            keySet = new KeySet<K, V>(this);
++        }
++        return keySet;
++    }
++
++    /**
++     * Creates a key set iterator.
++     * Subclasses can override this to return iterators with different properties.
++     *
++     * @param iterator the iterator to decorate
++     * @return the keySet iterator
++     */
++    protected Iterator<K> createKeySetIterator(Iterator<K> iterator) {
++        return new KeySetIterator<K, V>(iterator, this);
++    }
++
++    /**
++     * Gets a values view of the map.
++     * Changes made on the view are reflected in the map.
++     * The set supports remove and clear but not add.
++     *
++     * @return the values view
++     */
++    public Set<V> values() {
++        if (values == null) {
++            values = new Values<K, V>(this);
++        }
++        return values;
++    }
++
++    /**
++     * Creates a values iterator.
++     * Subclasses can override this to return iterators with different properties.
++     *
++     * @param iterator the iterator to decorate
++     * @return the values iterator
++     */
++    protected Iterator<V> createValuesIterator(Iterator<V> iterator) {
++        return new ValuesIterator<K, V>(iterator, this);
++    }
++
++    /**
++     * Gets an entrySet view of the map.
++     * Changes made on the set are reflected in the map.
++     * The set supports remove and clear but not add.
++     * <p/>
++     * The Map Entry setValue() method only allow a new value to be set.
++     * If the value being set is already in the map, an IllegalArgumentException
++     * is thrown (as setValue cannot change the size of the map).
++     *
++     * @return the entrySet view
++     */
++    public Set<Map.Entry<K, V>> entrySet() {
++        if (entrySet == null) {
++            entrySet = new EntrySet<K, V>(this);
++        }
++        return entrySet;
++    }
++
++    /**
++     * Creates an entry set iterator.
++     * Subclasses can override this to return iterators with different properties.
++     *
++     * @param iterator the iterator to decorate
++     * @return the entrySet iterator
++     */
++    protected Iterator<Map.Entry<K, V>> createEntrySetIterator(Iterator<Map.Entry<K, V>> iterator) {
++        return new EntrySetIterator<K, V>(iterator, this);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Inner class View.
++     */
++    protected static abstract class View <K,V,E> extends AbstractCollectionDecorator<E> {
++
++        /**
++         * The parent map
++         */
++        protected final AbstractDualBidiMap<K, V> parent;
++
++        /**
++         * Constructs a new view of the BidiMap.
++         *
++         * @param coll   the collection view being decorated
++         * @param parent the parent BidiMap
++         */
++        protected View(Collection<E> coll, AbstractDualBidiMap<K, V> parent) {
++            super(coll);
++            this.parent = parent;
++        }
++
++        public boolean removeAll(Collection<?> coll) {
++            if (parent.isEmpty() || coll.isEmpty()) {
++                return false;
++            }
++            boolean modified = false;
++            Iterator it = iterator();
++            while (it.hasNext()) {
++                if (coll.contains(it.next())) {
++                    it.remove();
++                    modified = true;
++                }
++            }
++            return modified;
++        }
++
++        public boolean retainAll(Collection<?> coll) {
++            if (parent.isEmpty()) {
++                return false;
++            }
++            if (coll.isEmpty()) {
++                parent.clear();
++                return true;
++            }
++            boolean modified = false;
++            Iterator it = iterator();
++            while (it.hasNext()) {
++                if (coll.contains(it.next()) == false) {
++                    it.remove();
++                    modified = true;
++                }
++            }
++            return modified;
++        }
++
++        public void clear() {
++            parent.clear();
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Inner class KeySet.
++     */
++    protected static class KeySet <K,V> extends View<K, V, K> implements Set<K> {
++
++        /**
++         * Constructs a new view of the BidiMap.
++         *
++         * @param parent the parent BidiMap
++         */
++        protected KeySet(AbstractDualBidiMap<K, V> parent) {
++            super(parent.forwardMap.keySet(), parent);
++        }
++
++        public Iterator<K> iterator() {
++            return parent.createKeySetIterator(super.iterator());
++        }
++
++        public boolean contains(Object key) {
++            return parent.forwardMap.containsKey(key);
++        }
++
++        public boolean remove(Object key) {
++            if (parent.forwardMap.containsKey(key)) {
++                Object value = parent.forwardMap.remove(key);
++                parent.inverseMap.remove(value);
++                return true;
++            }
++            return false;
++        }
++    }
++
++    /**
++     * Inner class KeySetIterator.
++     */
++    protected static class KeySetIterator <K,V> extends AbstractIteratorDecorator<K> {
++
++        /**
++         * The parent map
++         */
++        protected final AbstractDualBidiMap<K, V> parent;
++        /**
++         * The last returned key
++         */
++        protected K lastKey = null;
++        /**
++         * Whether remove is allowed at present
++         */
++        protected boolean canRemove = false;
++
++        /**
++         * Constructor.
++         *
++         * @param iterator the iterator to decorate
++         * @param parent   the parent map
++         */
++        protected KeySetIterator(Iterator<K> iterator, AbstractDualBidiMap<K, V> parent) {
++            super(iterator);
++            this.parent = parent;
++        }
++
++        public K next() {
++            lastKey = super.next();
++            canRemove = true;
++            return lastKey;
++        }
++
++        public void remove() {
++            if (canRemove == false) {
++                throw new IllegalStateException("Iterator remove() can only be called once after next()");
++            }
++            Object value = parent.forwardMap.get(lastKey);
++            super.remove();
++            parent.inverseMap.remove(value);
++            lastKey = null;
++            canRemove = false;
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Inner class Values.
++     */
++    protected static class Values <K,V> extends View<K, V, V> implements Set<V> {
++
++        /**
++         * Constructs a new view of the BidiMap.
++         *
++         * @param parent the parent BidiMap
++         */
++        protected Values(AbstractDualBidiMap<K, V> parent) {
++            super(parent.forwardMap.values(), parent);
++        }
++
++        public Iterator<V> iterator() {
++            return parent.createValuesIterator(super.iterator());
++        }
++
++        public boolean contains(Object value) {
++            return parent.inverseMap.containsKey(value);
++        }
++
++        public boolean remove(Object value) {
++            if (parent.inverseMap.containsKey(value)) {
++                Object key = parent.inverseMap.remove(value);
++                parent.forwardMap.remove(key);
++                return true;
++            }
++            return false;
++        }
++    }
++
++    /**
++     * Inner class ValuesIterator.
++     */
++    protected static class ValuesIterator <K,V> extends AbstractIteratorDecorator<V> {
++
++        /**
++         * The parent map
++         */
++        protected final AbstractDualBidiMap<K, V> parent;
++        /**
++         * The last returned value
++         */
++        protected V lastValue = null;
++        /**
++         * Whether remove is allowed at present
++         */
++        protected boolean canRemove = false;
++
++        /**
++         * Constructor.
++         *
++         * @param iterator the iterator to decorate
++         * @param parent   the parent map
++         */
++        protected ValuesIterator(Iterator<V> iterator, AbstractDualBidiMap<K, V> parent) {
++            super(iterator);
++            this.parent = parent;
++        }
++
++        public V next() {
++            lastValue = super.next();
++            canRemove = true;
++            return lastValue;
++        }
++
++        public void remove() {
++            if (canRemove == false) {
++                throw new IllegalStateException("Iterator remove() can only be called once after next()");
++            }
++            super.remove(); // removes from forwardMap
++            parent.inverseMap.remove(lastValue);
++            lastValue = null;
++            canRemove = false;
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Inner class EntrySet.
++     */
++    protected static class EntrySet <K,V> extends View<K, V, Map.Entry<K, V>> implements Set<Map.Entry<K, V>> {
++
++        /**
++         * Constructs a new view of the BidiMap.
++         *
++         * @param parent the parent BidiMap
++         */
++        protected EntrySet(AbstractDualBidiMap<K, V> parent) {
++            super(parent.forwardMap.entrySet(), parent);
++        }
++
++        public Iterator<Map.Entry<K, V>> iterator() {
++            return parent.createEntrySetIterator(super.iterator());
++        }
++
++        public boolean remove(Object obj) {
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++            Map.Entry entry = (Map.Entry) obj;
++            Object key = entry.getKey();
++            if (parent.containsKey(key)) {
++                Object value = parent.forwardMap.get(key);
++                if (value == null ? entry.getValue() == null : value.equals(entry.getValue())) {
++                    parent.forwardMap.remove(key);
++                    parent.inverseMap.remove(value);
++                    return true;
++                }
++            }
++            return false;
++        }
++    }
++
++    /**
++     * Inner class EntrySetIterator.
++     */
++    protected static class EntrySetIterator <K,V> extends AbstractIteratorDecorator<Map.Entry<K, V>> {
++
++        /**
++         * The parent map
++         */
++        protected final AbstractDualBidiMap<K, V> parent;
++        /**
++         * The last returned entry
++         */
++        protected Map.Entry<K, V> last = null;
++        /**
++         * Whether remove is allowed at present
++         */
++        protected boolean canRemove = false;
++
++        /**
++         * Constructor.
++         *
++         * @param iterator the iterator to decorate
++         * @param parent   the parent map
++         */
++        protected EntrySetIterator(Iterator<Map.Entry<K, V>> iterator, AbstractDualBidiMap<K, V> parent) {
++            super(iterator);
++            this.parent = parent;
++        }
++
++        public Map.Entry<K, V> next() {
++            last = new MapEntry<K, V>(super.next(), parent);
++            canRemove = true;
++            return last;
++        }
++
++        public void remove() {
++            if (canRemove == false) {
++                throw new IllegalStateException("Iterator remove() can only be called once after next()");
++            }
++            // store value as remove may change the entry in the decorator (eg.TreeMap)
++            Object value = last.getValue();
++            super.remove();
++            parent.inverseMap.remove(value);
++            last = null;
++            canRemove = false;
++        }
++    }
++
++    /**
++     * Inner class MapEntry.
++     */
++    protected static class MapEntry <K,V> extends AbstractMapEntryDecorator<K, V> {
++
++        /**
++         * The parent map
++         */
++        protected final AbstractDualBidiMap<K, V> parent;
++
++        /**
++         * Constructor.
++         *
++         * @param entry  the entry to decorate
++         * @param parent the parent map
++         */
++        protected MapEntry(Map.Entry<K, V> entry, AbstractDualBidiMap<K, V> parent) {
++            super(entry);
++            this.parent = parent;
++        }
++
++        public V setValue(V value) {
++            K key = MapEntry.this.getKey();
++            if (parent.inverseMap.containsKey(value) && parent.inverseMap.get(value) != key) {
++                throw new IllegalArgumentException("Cannot use setValue() when the object being set is already in the map");
++            }
++            parent.put(key, value);
++            final V oldValue = super.setValue(value);
++            return oldValue;
++        }
++    }
++
++    /**
++     * Inner class MapIterator.
++     */
++    protected static class BidiMapIterator <K,V> implements MapIterator<K, V>, ResettableIterator<K> {
++
++        /**
++         * The parent map
++         */
++        protected final AbstractDualBidiMap<K, V> parent;
++        /**
++         * The iterator being wrapped
++         */
++        protected Iterator<Map.Entry<K, V>> iterator;
++        /**
++         * The last returned entry
++         */
++        protected Map.Entry<K, V> last = null;
++        /**
++         * Whether remove is allowed at present
++         */
++        protected boolean canRemove = false;
++
++        /**
++         * Constructor.
++         *
++         * @param parent the parent map
++         */
++        protected BidiMapIterator(AbstractDualBidiMap<K, V> parent) {
++            super();
++            this.parent = parent;
++            this.iterator = parent.forwardMap.entrySet().iterator();
++        }
++
++        public boolean hasNext() {
++            return iterator.hasNext();
++        }
++
++        public K next() {
++            last = iterator.next();
++            canRemove = true;
++            return last.getKey();
++        }
++
++        public void remove() {
++            if (canRemove == false) {
++                throw new IllegalStateException("Iterator remove() can only be called once after next()");
++            }
++            // store value as remove may change the entry in the decorator (eg.TreeMap)
++            V value = last.getValue();
++            iterator.remove();
++            parent.inverseMap.remove(value);
++            last = null;
++            canRemove = false;
++        }
++
++        public K getKey() {
++            if (last == null) {
++                throw new IllegalStateException("Iterator getKey() can only be called after next() and before remove()");
++            }
++            return last.getKey();
++        }
++
++        public V getValue() {
++            if (last == null) {
++                throw new IllegalStateException("Iterator getValue() can only be called after next() and before remove()");
++            }
++            return last.getValue();
++        }
++
++        public V setValue(V value) {
++            if (last == null) {
++                throw new IllegalStateException("Iterator setValue() can only be called after next() and before remove()");
++            }
++            if (parent.inverseMap.containsKey(value) && parent.inverseMap.get(value) != last.getKey()) {
++                throw new IllegalArgumentException("Cannot use setValue() when the object being set is already in the map");
++            }
++            return parent.put(last.getKey(), value);
++        }
++
++        public void reset() {
++            iterator = parent.forwardMap.entrySet().iterator();
++            last = null;
++            canRemove = false;
++        }
++
++        public String toString() {
++            if (last != null) {
++                return "MapIterator[" + getKey() + "=" + getValue() + "]";
++            } else {
++                return "MapIterator[]";
++            }
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bidimap/AbstractOrderedBidiMapDecorator.java
+@@ -0,0 +1,84 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bidimap;
++
++import org.apache.commons.collections15.OrderedBidiMap;
++import org.apache.commons.collections15.OrderedMapIterator;
++
++/**
++ * Provides a base decorator that enables additional functionality to be added
++ * to an OrderedBidiMap via decoration.
++ * <p/>
++ * Methods are forwarded directly to the decorated map.
++ * <p/>
++ * This implementation does not perform any special processing with the map views.
++ * Instead it simply returns the inverse from the wrapped map. This may be
++ * undesirable, for example if you are trying to write a validating implementation
++ * it would provide a loophole around the validation.
++ * But, you might want that loophole, so this class is kept simple.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractOrderedBidiMapDecorator <K,V> extends AbstractBidiMapDecorator<K, V> implements OrderedBidiMap<K, V> {
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    protected AbstractOrderedBidiMapDecorator(OrderedBidiMap<K, V> map) {
++        super(map);
++    }
++
++    /**
++     * Gets the map being decorated.
++     *
++     * @return the decorated map
++     */
++    protected OrderedBidiMap<K, V> getOrderedBidiMap() {
++        return (OrderedBidiMap<K, V>) map;
++    }
++
++    //-----------------------------------------------------------------------
++    public OrderedMapIterator<K, V> orderedMapIterator() {
++        return getOrderedBidiMap().orderedMapIterator();
++    }
++
++    public K firstKey() {
++        return getOrderedBidiMap().firstKey();
++    }
++
++    public K lastKey() {
++        return getOrderedBidiMap().lastKey();
++    }
++
++    public K nextKey(K key) {
++        return getOrderedBidiMap().nextKey(key);
++    }
++
++    public K previousKey(K key) {
++        return getOrderedBidiMap().previousKey(key);
++    }
++
++    public OrderedBidiMap<V, K> inverseOrderedBidiMap() {
++        return getOrderedBidiMap().inverseOrderedBidiMap();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bidimap/AbstractSortedBidiMapDecorator.java
+@@ -0,0 +1,82 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bidimap;
++
++import org.apache.commons.collections15.SortedBidiMap;
++
++import java.util.Comparator;
++import java.util.SortedMap;
++
++/**
++ * Provides a base decorator that enables additional functionality to be added
++ * to a SortedBidiMap via decoration.
++ * <p/>
++ * Methods are forwarded directly to the decorated map.
++ * <p/>
++ * This implementation does not perform any special processing with the map views.
++ * Instead it simply returns the inverse from the wrapped map. This may be
++ * undesirable, for example if you are trying to write a validating implementation
++ * it would provide a loophole around the validation.
++ * But, you might want that loophole, so this class is kept simple.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractSortedBidiMapDecorator <K,V> extends AbstractOrderedBidiMapDecorator<K, V> implements SortedBidiMap<K, V> {
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    public AbstractSortedBidiMapDecorator(SortedBidiMap<K, V> map) {
++        super(map);
++    }
++
++    /**
++     * Gets the map being decorated.
++     *
++     * @return the decorated map
++     */
++    protected SortedBidiMap<K, V> getSortedBidiMap() {
++        return (SortedBidiMap<K, V>) map;
++    }
++
++    //-----------------------------------------------------------------------
++    public SortedBidiMap<V, K> inverseSortedBidiMap() {
++        return getSortedBidiMap().inverseSortedBidiMap();
++    }
++
++    public Comparator<? super K> comparator() {
++        return getSortedBidiMap().comparator();
++    }
++
++    public SortedMap<K, V> subMap(K fromKey, K toKey) {
++        return getSortedBidiMap().subMap(fromKey, toKey);
++    }
++
++    public SortedMap<K, V> headMap(K toKey) {
++        return getSortedBidiMap().headMap(toKey);
++    }
++
++    public SortedMap<K, V> tailMap(K fromKey) {
++        return getSortedBidiMap().tailMap(fromKey);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bidimap/DualHashBidiMap.java
+@@ -0,0 +1,107 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bidimap;
++
++import org.apache.commons.collections15.BidiMap;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.HashMap;
++import java.util.Map;
++
++/**
++ * Implementation of <code>BidiMap</code> that uses two <code>HashMap</code> instances.
++ * <p/>
++ * Two <code>HashMap</code> instances are used in this class.
++ * This provides fast lookups at the expense of storing two sets of map entries.
++ * Commons Collections would welcome the addition of a direct hash-based
++ * implementation of the <code>BidiMap</code> interface.
++ * <p/>
++ * NOTE: From Commons Collections 3.1, all subclasses will use <code>HashMap</code>
++ * and the flawed <code>createMap</code> method is ignored.
++ *
++ * @author Matthew Hawthorne
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Id: DualHashBidiMap.java,v 1.1 2005/10/11 17:05:19 pents90 Exp $
++ * @since Commons Collections 3.0
++ */
++public class DualHashBidiMap <K,V> extends AbstractDualBidiMap<K, V> implements Serializable {
++
++    /**
++     * Ensure serialization compatibility
++     */
++    private static final long serialVersionUID = 721969328361808L;
++
++    /**
++     * Creates an empty <code>HashBidiMap</code>.
++     */
++    public DualHashBidiMap() {
++        super(new HashMap<K, V>(), new HashMap<V, K>());
++    }
++
++    /**
++     * Constructs a <code>HashBidiMap</code> and copies the mappings from
++     * specified <code>Map</code>.
++     *
++     * @param map the map whose mappings are to be placed in this map
++     */
++    public DualHashBidiMap(Map<? extends K, ? extends V> map) {
++        super(new HashMap<K, V>(), new HashMap<V, K>());
++        putAll(map);
++    }
++
++    /**
++     * Constructs a <code>HashBidiMap</code> that decorates the specified maps.
++     *
++     * @param normalMap      the normal direction map
++     * @param reverseMap     the reverse direction map
++     * @param inverseBidiMap the inverse BidiMap
++     */
++    protected DualHashBidiMap(Map<K, V> normalMap, Map<V, K> reverseMap, BidiMap<V, K> inverseBidiMap) {
++        super(normalMap, reverseMap, inverseBidiMap);
++    }
++
++    /**
++     * Creates a new instance of this object.
++     *
++     * @param normalMap      the normal direction map
++     * @param reverseMap     the reverse direction map
++     * @param inverseBidiMap the inverse BidiMap
++     * @return new bidi map
++     */
++    protected <K,V> BidiMap<K, V> createBidiMap(Map<K, V> normalMap, Map<V, K> reverseMap, BidiMap<V, K> inverseBidiMap) {
++        return new DualHashBidiMap<K, V>(normalMap, reverseMap, inverseBidiMap);
++    }
++
++    // Serialization
++    //-----------------------------------------------------------------------
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(forwardMap);
++    }
++
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        forwardMap = new HashMap<K, V>();
++        inverseMap = new HashMap<V, K>();
++        Map<K, V> map = (Map<K, V>) in.readObject();
++        putAll(map);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bidimap/DualTreeBidiMap.java
+@@ -0,0 +1,353 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bidimap;
++
++import org.apache.commons.collections15.*;
++import org.apache.commons.collections15.map.AbstractSortedMapDecorator;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.*;
++
++/**
++ * Implementation of <code>BidiMap</code> that uses two <code>TreeMap</code> instances.
++ * <p/>
++ * The setValue() method on iterators will succeed only if the new value being set is
++ * not already in the bidimap.
++ * <p/>
++ * When considering whether to use this class, the {@link TreeBidiMap} class should
++ * also be considered. It implements the interface using a dedicated design, and does
++ * not store each object twice, which can save on memory use.
++ * <p/>
++ * NOTE: From Commons Collections 3.1, all subclasses will use <code>TreeMap</code>
++ * and the flawed <code>createMap</code> method is ignored.
++ *
++ * @author Matthew Hawthorne
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Id: DualTreeBidiMap.java,v 1.1 2005/10/11 17:05:19 pents90 Exp $
++ * @since Commons Collections 3.0
++ */
++public class DualTreeBidiMap <K,V> extends AbstractDualBidiMap<K, V> implements SortedBidiMap<K, V>, Serializable {
++
++    /**
++     * Ensure serialization compatibility
++     */
++    private static final long serialVersionUID = 721969328361809L;
++    /**
++     * The comparator to use
++     */
++    protected final Comparator<? super K> comparator;
++
++    /**
++     * Creates an empty <code>DualTreeBidiMap</code>
++     */
++    public DualTreeBidiMap() {
++        super(new TreeMap<K, V>(), new TreeMap<V, K>());
++        this.comparator = null;
++    }
++
++    public static <E> DualTreeBidiMap<E, E> createTwoWayBidiMap(Comparator<? super E> comparator) {
++        return new DualTreeBidiMap<E, E>(comparator, comparator);
++    }
++
++    /**
++     * Constructs a <code>DualTreeBidiMap</code> and copies the mappings from
++     * specified <code>Map</code>.
++     *
++     * @param map the map whose mappings are to be placed in this map
++     */
++    public DualTreeBidiMap(Map<? extends K, ? extends V> map) {
++        super(new TreeMap<K, V>(), new TreeMap<V, K>());
++        putAll(map);
++        this.comparator = null;
++    }
++
++    /**
++     * Constructs a <code>DualTreeBidiMap</code> using the specified Comparators.
++     *
++     * @param comparator the Comparator
++     */
++    public DualTreeBidiMap(Comparator<? super K> comparator, Comparator<? super V> inverseComparator) {
++        super(new TreeMap<K, V>(comparator), new TreeMap<V, K>(inverseComparator));
++        this.comparator = comparator;
++    }
++
++    /**
++     * Constructs a <code>DualTreeBidiMap</code> that decorates the specified maps.
++     *
++     * @param normalMap      the normal direction map
++     * @param reverseMap     the reverse direction map
++     * @param inverseBidiMap the inverse BidiMap
++     */
++    protected DualTreeBidiMap(Map<K, V> normalMap, Map<V, K> reverseMap, BidiMap<V, K> inverseBidiMap) {
++        super(normalMap, reverseMap, inverseBidiMap);
++        this.comparator = ((SortedMap<K, V>) normalMap).comparator();
++    }
++
++    /**
++     * Creates a new instance of this object.
++     *
++     * @param normalMap  the normal direction map
++     * @param reverseMap the reverse direction map
++     * @param inverseMap the inverse BidiMap
++     * @return new bidi map
++     */
++    protected <K,V> BidiMap<K, V> createBidiMap(Map<K, V> normalMap, Map<V, K> reverseMap, BidiMap<V, K> inverseMap) {
++        return new DualTreeBidiMap<K, V>(normalMap, reverseMap, inverseMap);
++    }
++
++    //-----------------------------------------------------------------------
++    public Comparator<? super K> comparator() {
++        return ((SortedMap<K, V>) forwardMap).comparator();
++    }
++
++    public K firstKey() {
++        return ((SortedMap<K, V>) forwardMap).firstKey();
++    }
++
++    public K lastKey() {
++        return ((SortedMap<K, V>) forwardMap).lastKey();
++    }
++
++    public K nextKey(K key) {
++        if (isEmpty()) {
++            return null;
++        }
++        if (forwardMap instanceof OrderedMap) {
++            return ((OrderedMap<K, V>) forwardMap).nextKey(key);
++        }
++        SortedMap sm = (SortedMap) forwardMap;
++        Iterator<K> it = sm.tailMap(key).keySet().iterator();
++        it.next();
++        if (it.hasNext()) {
++            return it.next();
++        }
++        return null;
++    }
++
++    public K previousKey(K key) {
++        if (isEmpty()) {
++            return null;
++        }
++        if (forwardMap instanceof OrderedMap) {
++            return ((OrderedMap<K, V>) forwardMap).previousKey(key);
++        }
++        SortedMap<K, V> sm = (SortedMap<K, V>) forwardMap;
++        SortedMap<K, V> hm = sm.headMap(key);
++        if (hm.isEmpty()) {
++            return null;
++        }
++        return hm.lastKey();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Obtains an ordered map iterator.
++     * <p/>
++     * This implementation copies the elements to an ArrayList in order to
++     * provide the forward/backward behaviour.
++     *
++     * @return a new ordered map iterator
++     */
++    public OrderedMapIterator<K, V> orderedMapIterator() {
++        return new BidiOrderedMapIterator<K, V>(this);
++    }
++
++    public SortedBidiMap<V, K> inverseSortedBidiMap() {
++        return (SortedBidiMap<V, K>) inverseBidiMap();
++    }
++
++    public OrderedBidiMap<V, K> inverseOrderedBidiMap() {
++        return (OrderedBidiMap<V, K>) inverseBidiMap();
++    }
++
++    //-----------------------------------------------------------------------
++    public SortedMap<K, V> headMap(K toKey) {
++        SortedMap<K, V> sub = ((SortedMap<K, V>) forwardMap).headMap(toKey);
++        return new ViewMap(this, sub);
++    }
++
++    public SortedMap<K, V> tailMap(K fromKey) {
++        SortedMap<K, V> sub = ((SortedMap<K, V>) forwardMap).tailMap(fromKey);
++        return new ViewMap<K, V>(this, sub);
++    }
++
++    public SortedMap<K, V> subMap(K fromKey, K toKey) {
++        SortedMap<K, V> sub = ((SortedMap<K, V>) forwardMap).subMap(fromKey, toKey);
++        return new ViewMap<K, V>(this, sub);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Internal sorted map view.
++     */
++    protected static class ViewMap <K,V> extends AbstractSortedMapDecorator<K, V> {
++        /**
++         * The parent bidi map.
++         */
++        final DualTreeBidiMap<K, V> bidi;
++
++        /**
++         * Constructor.
++         *
++         * @param bidi the parent bidi map
++         * @param sm   the subMap sorted map
++         */
++        protected ViewMap(DualTreeBidiMap<K, V> bidi, SortedMap<K, V> sm) {
++            // the implementation is not great here...
++            // use the forwardMap as the filtered map, but inverseMap as the full map
++            // this forces containsValue and clear to be overridden
++            super((SortedMap) bidi.createBidiMap(sm, bidi.inverseMap, bidi.inverseBidiMap));
++            this.bidi = (DualTreeBidiMap) map;
++        }
++
++        public boolean containsValue(Object value) {
++            // override as default implementation jumps to [1]
++            return bidi.forwardMap.containsValue(value);
++        }
++
++        public void clear() {
++            // override as default implementation jumps to [1]
++            for (Iterator it = keySet().iterator(); it.hasNext();) {
++                it.next();
++                it.remove();
++            }
++        }
++
++        public SortedMap<K, V> headMap(K toKey) {
++            return new ViewMap<K, V>(bidi, super.headMap(toKey));
++        }
++
++        public SortedMap<K, V> tailMap(K fromKey) {
++            return new ViewMap<K, V>(bidi, super.tailMap(fromKey));
++        }
++
++        public SortedMap<K, V> subMap(K fromKey, K toKey) {
++            return new ViewMap<K, V>(bidi, super.subMap(fromKey, toKey));
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Inner class MapIterator.
++     */
++    protected static class BidiOrderedMapIterator <K,V> implements OrderedMapIterator<K, V>, ResettableIterator<K> {
++
++        /**
++         * The parent map
++         */
++        protected final AbstractDualBidiMap<K, V> parent;
++        /**
++         * The iterator being decorated
++         */
++        protected ListIterator<Map.Entry<K, V>> iterator;
++        /**
++         * The last returned entry
++         */
++        private Map.Entry<K, V> last = null;
++
++        /**
++         * Constructor.
++         *
++         * @param parent the parent map
++         */
++        protected BidiOrderedMapIterator(AbstractDualBidiMap<K, V> parent) {
++            super();
++            this.parent = parent;
++            iterator = new ArrayList<Map.Entry<K, V>>(parent.entrySet()).listIterator();
++        }
++
++        public boolean hasNext() {
++            return iterator.hasNext();
++        }
++
++        public K next() {
++            last = iterator.next();
++            return last.getKey();
++        }
++
++        public boolean hasPrevious() {
++            return iterator.hasPrevious();
++        }
++
++        public K previous() {
++            last = iterator.previous();
++            return last.getKey();
++        }
++
++        public void remove() {
++            iterator.remove();
++            parent.remove(last.getKey());
++            last = null;
++        }
++
++        public K getKey() {
++            if (last == null) {
++                throw new IllegalStateException("Iterator getKey() can only be called after next() and before remove()");
++            }
++            return last.getKey();
++        }
++
++        public V getValue() {
++            if (last == null) {
++                throw new IllegalStateException("Iterator getValue() can only be called after next() and before remove()");
++            }
++            return last.getValue();
++        }
++
++        public V setValue(V value) {
++            if (last == null) {
++                throw new IllegalStateException("Iterator setValue() can only be called after next() and before remove()");
++            }
++            if (parent.inverseMap.containsKey(value) && parent.inverseMap.get(value) != last.getKey()) {
++                throw new IllegalArgumentException("Cannot use setValue() when the object being set is already in the map");
++            }
++            return parent.put(last.getKey(), value);
++        }
++
++        public void reset() {
++            iterator = new ArrayList<Map.Entry<K, V>>(parent.entrySet()).listIterator();
++            last = null;
++        }
++
++        public String toString() {
++            if (last != null) {
++                return "MapIterator[" + getKey() + "=" + getValue() + "]";
++            } else {
++                return "MapIterator[]";
++            }
++        }
++    }
++
++    // Serialization
++    //-----------------------------------------------------------------------
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(forwardMap);
++    }
++
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        forwardMap = new TreeMap<K, V>(comparator);
++        inverseMap = new TreeMap<V, K>();
++        Map<K, V> map = (Map<K, V>) in.readObject();
++        putAll(map);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bidimap/TreeBidiMap.java
+@@ -0,0 +1,2144 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bidimap;
++
++import org.apache.commons.collections15.*;
++import org.apache.commons.collections15.iterators.EmptyOrderedMapIterator;
++import org.apache.commons.collections15.keyvalue.UnmodifiableMapEntry;
++
++import java.util.*;
++
++/**
++ * Red-Black tree-based implementation of BidiMap where all objects added
++ * implement the <code>Comparable</code> interface.
++ * <p/>
++ * This class guarantees that the map will be in both ascending key order
++ * and ascending value order, sorted according to the natural order for
++ * the key's and value's classes.
++ * <p/>
++ * This Map is intended for applications that need to be able to look
++ * up a key-value pairing by either key or value, and need to do so
++ * with equal efficiency.
++ * <p/>
++ * While that goal could be accomplished by taking a pair of TreeMaps
++ * and redirecting requests to the appropriate TreeMap (e.g.,
++ * containsKey would be directed to the TreeMap that maps values to
++ * keys, containsValue would be directed to the TreeMap that maps keys
++ * to values), there are problems with that implementation.
++ * If the data contained in the TreeMaps is large, the cost of redundant
++ * storage becomes significant. The {@link DualTreeBidiMap} and
++ * {@link DualHashBidiMap} implementations use this approach.
++ * <p/>
++ * This solution keeps minimizes the data storage by holding data only once.
++ * The red-black algorithm is based on java util TreeMap, but has been modified
++ * to simultaneously map a tree node by key and by value. This doubles the
++ * cost of put operations (but so does using two TreeMaps), and nearly doubles
++ * the cost of remove operations (there is a savings in that the lookup of the
++ * node to be removed only has to be performed once). And since only one node
++ * contains the key and value, storage is significantly less than that
++ * required by two TreeMaps.
++ * <p/>
++ * The Map.Entry instances returned by the appropriate methods will
++ * not allow setValue() and will throw an
++ * UnsupportedOperationException on attempts to call that method.
++ *
++ * @author Marc Johnson
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0 (previously DoubleOrderedMap v2.0)
++ */
++public class TreeBidiMap <K extends Comparable,V extends Comparable> implements OrderedBidiMap<K, V> {
++
++    private static final int KEY = 0;
++    private static final int VALUE = 1;
++    private static final int MAPENTRY = 2;
++    private static final int INVERSEMAPENTRY = 3;
++    private static final int SUM_OF_INDICES = KEY + VALUE;
++    private static final int FIRST_INDEX = 0;
++    private static final int NUMBER_OF_INDICES = 2;
++    private static final String[] dataName = new String[]{"key", "value"};
++
++    private Node<K, V>[] rootNode = new Node[2];
++    private int nodeCount = 0;
++    private int modifications = 0;
++    private Set<K> keySet;
++    private Set<V> valuesSet;
++    private Set entrySet;
++    private TreeBidiMap.Inverse<K, V> inverse = null;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructs a new empty TreeBidiMap.
++     */
++    public TreeBidiMap() {
++        super();
++    }
++
++    /**
++     * Constructs a new TreeBidiMap by copying an existing Map.
++     *
++     * @param map the map to copy
++     * @throws ClassCastException   if the keys/values in the map are
++     *                              not Comparable or are not mutually comparable
++     * @throws NullPointerException if any key or value in the map is null
++     */
++    public TreeBidiMap(final Map map) {
++        super();
++        putAll(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns the number of key-value mappings in this map.
++     *
++     * @return the number of key-value mappings in this map
++     */
++    public int size() {
++        return nodeCount;
++    }
++
++    /**
++     * Checks whether the map is empty or not.
++     *
++     * @return true if the map is empty
++     */
++    public boolean isEmpty() {
++        return (nodeCount == 0);
++    }
++
++    /**
++     * Checks whether this map contains the a mapping for the specified key.
++     * <p/>
++     * The key must implement <code>Comparable</code>.
++     *
++     * @param key key whose presence in this map is to be tested
++     * @return true if this map contains a mapping for the specified key
++     * @throws ClassCastException   if the key is of an inappropriate type
++     * @throws NullPointerException if the key is null
++     */
++    public boolean containsKey(final Object key) {
++        checkKey(key);
++        return (lookup((Comparable) key, KEY) != null);
++    }
++
++    /**
++     * Checks whether this map contains the a mapping for the specified value.
++     * <p/>
++     * The value must implement <code>Comparable</code>.
++     *
++     * @param value value whose presence in this map is to be tested
++     * @return true if this map contains a mapping for the specified value
++     * @throws ClassCastException   if the value is of an inappropriate type
++     * @throws NullPointerException if the value is null
++     */
++    public boolean containsValue(final Object value) {
++        checkValue(value);
++        return (lookup((Comparable) value, VALUE) != null);
++    }
++
++    /**
++     * Gets the value to which this map maps the specified key.
++     * Returns null if the map contains no mapping for this key.
++     * <p/>
++     * The key must implement <code>Comparable</code>.
++     *
++     * @param key key whose associated value is to be returned
++     * @return the value to which this map maps the specified key,
++     *         or null if the map contains no mapping for this key
++     * @throws ClassCastException   if the key is of an inappropriate type
++     * @throws NullPointerException if the key is null
++     */
++    public V get(final Object key) {
++        return doGetValue(key);
++    }
++
++    /**
++     * Puts the key-value pair into the map, replacing any previous pair.
++     * <p/>
++     * When adding a key-value pair, the value may already exist in the map
++     * against a different key. That mapping is removed, to ensure that the
++     * value only occurs once in the inverse map.
++     * <pre>
++     *  BidiMap map1 = new TreeBidiMap();
++     *  map.put("A","B");  // contains A mapped to B, as per Map
++     *  map.put("A","C");  // contains A mapped to C, as per Map
++     * <p/>
++     *  BidiMap map2 = new TreeBidiMap();
++     *  map.put("A","B");  // contains A mapped to B, as per Map
++     *  map.put("C","B");  // contains C mapped to B, key A is removed
++     * </pre>
++     * <p/>
++     * Both key and value must implement <code>Comparable</code>.
++     *
++     * @param key   key with which the specified value is to be  associated
++     * @param value value to be associated with the specified key
++     * @return the previous value for the key
++     * @throws ClassCastException   if the key is of an inappropriate type
++     * @throws NullPointerException if the key is null
++     */
++    public V put(final K key, final V value) {
++        return doPutByKey(key, value);
++    }
++
++    /**
++     * Puts all the mappings from the specified map into this map.
++     * <p/>
++     * All keys and values must implement <code>Comparable</code>.
++     *
++     * @param map the map to copy from
++     */
++    public void putAll(Map<? extends K, ? extends V> map) {
++        Iterator it = map.entrySet().iterator();
++        while (it.hasNext()) {
++            Map.Entry entry = (Map.Entry) it.next();
++            put((K) entry.getKey(), (V) entry.getValue());
++        }
++    }
++
++    /**
++     * Removes the mapping for this key from this map if present.
++     * <p/>
++     * The key must implement <code>Comparable</code>.
++     *
++     * @param key key whose mapping is to be removed from the map.
++     * @return previous value associated with specified key,
++     *         or null if there was no mapping for key.
++     * @throws ClassCastException   if the key is of an inappropriate type
++     * @throws NullPointerException if the key is null
++     */
++    public V remove(final Object key) {
++        return doRemoveByKey((K) key);
++    }
++
++    /**
++     * Removes all mappings from this map.
++     */
++    public void clear() {
++        modify();
++
++        nodeCount = 0;
++        rootNode[KEY] = null;
++        rootNode[VALUE] = null;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns the key to which this map maps the specified value.
++     * Returns null if the map contains no mapping for this value.
++     * <p/>
++     * The value must implement <code>Comparable</code>.
++     *
++     * @param value value whose associated key is to be returned.
++     * @return the key to which this map maps the specified value,
++     *         or null if the map contains no mapping for this value.
++     * @throws ClassCastException   if the value is of an inappropriate type
++     * @throws NullPointerException if the value is null
++     */
++    public K getKey(final Object value) {
++        return doGetKey((Comparable) value);
++    }
++
++    /**
++     * Removes the mapping for this value from this map if present.
++     * <p/>
++     * The value must implement <code>Comparable</code>.
++     *
++     * @param value value whose mapping is to be removed from the map
++     * @return previous key associated with specified value,
++     *         or null if there was no mapping for value.
++     * @throws ClassCastException   if the value is of an inappropriate type
++     * @throws NullPointerException if the value is null
++     */
++    public K removeValue(final Object value) {
++        return doRemoveByValue((Comparable) value);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the first (lowest) key currently in this map.
++     *
++     * @return the first (lowest) key currently in this sorted map
++     * @throws NoSuchElementException if this map is empty
++     */
++    public K firstKey() {
++        if (nodeCount == 0) {
++            throw new NoSuchElementException("Map is empty");
++        }
++        return leastNode(rootNode[KEY], KEY).getKey();
++    }
++
++    /**
++     * Gets the last (highest) key currently in this map.
++     *
++     * @return the last (highest) key currently in this sorted map
++     * @throws NoSuchElementException if this map is empty
++     */
++    public K lastKey() {
++        if (nodeCount == 0) {
++            throw new NoSuchElementException("Map is empty");
++        }
++        return greatestNode(rootNode[KEY], KEY).getKey();
++    }
++
++    /**
++     * Gets the next key after the one specified.
++     * <p/>
++     * The key must implement <code>Comparable</code>.
++     *
++     * @param key the key to search for next from
++     * @return the next key, null if no match or at end
++     */
++    public K nextKey(K key) {
++        checkKey(key);
++        Node<K, V> node = nextGreater(lookup(key, KEY), KEY);
++        return (node == null ? null : node.getKey());
++    }
++
++    /**
++     * Gets the previous key before the one specified.
++     * <p/>
++     * The key must implement <code>Comparable</code>.
++     *
++     * @param key the key to search for previous from
++     * @return the previous key, null if no match or at start
++     */
++    public K previousKey(K key) {
++        checkKey(key);
++        Node<K, V> node = nextSmaller(lookup((Comparable) key, KEY), KEY);
++        return (node == null ? null : node.getKey());
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a set view of the keys contained in this map in key order.
++     * <p/>
++     * The set is backed by the map, so changes to the map are reflected in
++     * the set, and vice-versa. If the map is modified while an iteration over
++     * the set is in progress, the results of the iteration are undefined.
++     * <p/>
++     * The set supports element removal, which removes the corresponding mapping
++     * from the map. It does not support the add or addAll operations.
++     *
++     * @return a set view of the keys contained in this map.
++     */
++    public Set<K> keySet() {
++        if (keySet == null) {
++            keySet = new View(this, KEY, KEY);
++        }
++        return keySet;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a set view of the values contained in this map in key order.
++     * The returned object can be cast to a Set.
++     * <p/>
++     * The set is backed by the map, so changes to the map are reflected in
++     * the set, and vice-versa. If the map is modified while an iteration over
++     * the set is in progress, the results of the iteration are undefined.
++     * <p/>
++     * The set supports element removal, which removes the corresponding mapping
++     * from the map. It does not support the add or addAll operations.
++     *
++     * @return a set view of the values contained in this map.
++     */
++    public Set<V> values() {
++        if (valuesSet == null) {
++            valuesSet = new View(this, KEY, VALUE);
++        }
++        return valuesSet;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a set view of the entries contained in this map in key order.
++     * For simple iteration through the map, the MapIterator is quicker.
++     * <p/>
++     * The set is backed by the map, so changes to the map are reflected in
++     * the set, and vice-versa. If the map is modified while an iteration over
++     * the set is in progress, the results of the iteration are undefined.
++     * <p/>
++     * The set supports element removal, which removes the corresponding mapping
++     * from the map. It does not support the add or addAll operations.
++     * The returned MapEntry objects do not support setValue.
++     *
++     * @return a set view of the values contained in this map.
++     */
++    public Set<Map.Entry<K, V>> entrySet() {
++        if (entrySet == null) {
++            return new EntryView(this, KEY, MAPENTRY);
++        }
++        return entrySet;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator over the map entries.
++     * <p/>
++     * For this map, this iterator is the fastest way to iterate over the entries.
++     *
++     * @return an iterator
++     */
++    public MapIterator<K, V> mapIterator() {
++        if (isEmpty()) {
++            return EmptyOrderedMapIterator.INSTANCE;
++        }
++        return new ViewMapIterator(this, KEY);
++    }
++
++    /**
++     * Gets an ordered iterator over the map entries.
++     * <p/>
++     * This iterator allows both forward and reverse iteration over the entries.
++     *
++     * @return an iterator
++     */
++    public OrderedMapIterator<K, V> orderedMapIterator() {
++        if (isEmpty()) {
++            return EmptyOrderedMapIterator.INSTANCE;
++        }
++        return new ViewMapIterator(this, KEY);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the inverse map for comparison.
++     *
++     * @return the inverse map
++     */
++    public BidiMap<V, K> inverseBidiMap() {
++        return inverseOrderedBidiMap();
++    }
++
++    /**
++     * Gets the inverse map for comparison.
++     *
++     * @return the inverse map
++     */
++    public OrderedBidiMap<V, K> inverseOrderedBidiMap() {
++        if (inverse == null) {
++            inverse = new Inverse<K, V>(this);
++        }
++        return inverse;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Compares for equals as per the API.
++     *
++     * @param obj the object to compare to
++     * @return true if equal
++     */
++    public boolean equals(Object obj) {
++        return this.doEquals(obj, KEY);
++    }
++
++    /**
++     * Gets the hash code value for this map as per the API.
++     *
++     * @return the hash code value for this map
++     */
++    public int hashCode() {
++        return this.doHashCode(KEY);
++    }
++
++    /**
++     * Returns a string version of this Map in standard format.
++     *
++     * @return a standard format string version of the map
++     */
++    public String toString() {
++        return this.doToString(KEY);
++    }
++    
++    //-----------------------------------------------------------------------
++
++    /**
++     * Common get logic, used to get by value
++     *
++     * @param value the key or value that we're looking for
++     * @return the key (if the value was mapped) or the value (if the
++     *         key was mapped); null if we couldn't find the specified
++     *         object
++     */
++    private K doGetKey(final Comparable value) {
++        checkNonNullComparable(value);
++        Node<K, V> node = lookup(value, VALUE);
++        if (node == null) {
++            return null;
++        } else {
++            return node.getKey();
++        }
++    }
++
++    /**
++     * Common get logic, used to get by key
++     *
++     * @param key the key or value that we're looking for
++     * @return the key (if the value was mapped) or the value (if the
++     *         key was mapped); null if we couldn't find the specified
++     *         object
++     */
++    private V doGetValue(final Object key) {
++        checkNonNullComparable(key);
++        Node<K, V> node = lookup((Comparable) key, KEY);
++        if (node == null) {
++            return null;
++        } else {
++            return node.getValue();
++        }
++    }
++
++    /**
++     * Common put logic
++     *
++     * @param key   the key, always the main map key
++     * @param value the value, always the main map value
++     * @return the previously mapped value
++     */
++    private V doPutByKey(final K key, final V value) {
++        checkKeyAndValue(key, value);
++        
++        // store previous and remove previous mappings
++        V prev = doGetValue(key);
++
++        doPut(key, value);
++        return prev;
++    }
++
++    /**
++     * Common put logic
++     *
++     * @param key   the key, always the main map key
++     * @param value the value, always the main map value
++     * @return the previously mapped value
++     */
++    private K doPutByValue(final K key, final V value) {
++        checkKeyAndValue(key, value);
++
++        // store previous and remove previous mappings
++        K prev = doGetKey(value);
++
++        doPut(key, value);
++        return prev;
++    }
++
++    private void doPut(final K key, final V value) {
++        doRemoveByKey(key);
++        doRemoveByValue(value);
++        Node<K, V> node = rootNode[KEY];
++        if (node == null) {
++            // map is empty
++            Node<K, V> root = new Node<K, V>(key, value);
++            rootNode[KEY] = root;
++            rootNode[VALUE] = root;
++            grow();
++
++        } else {
++            // add new mapping
++            while (true) {
++                int cmp = compare(key, node.getKey());
++
++                if (cmp == 0) {
++                    // shouldn't happen
++                    throw new IllegalArgumentException("Cannot store a duplicate key (\"" + key + "\") in this Map");
++                } else if (cmp < 0) {
++                    if (node.getLeft(KEY) != null) {
++                        node = node.getLeft(KEY);
++                    } else {
++                        Node<K, V> newNode = new Node<K, V>(key, value);
++
++                        insertValue(newNode);
++                        node.setLeft(newNode, KEY);
++                        newNode.setParent(node, KEY);
++                        doRedBlackInsert(newNode, KEY);
++                        grow();
++
++                        break;
++                    }
++                } else { // cmp > 0
++                    if (node.getRight(KEY) != null) {
++                        node = node.getRight(KEY);
++                    } else {
++                        Node<K, V> newNode = new Node<K, V>(key, value);
++
++                        insertValue(newNode);
++                        node.setRight(newNode, KEY);
++                        newNode.setParent(node, KEY);
++                        doRedBlackInsert(newNode, KEY);
++                        grow();
++
++                        break;
++                    }
++                }
++            }
++        }
++    }
++
++    /**
++     * Remove by key
++     *
++     * @param key the key
++     * @return the key, if remove by value, or the value, if remove by
++     *         key. null if the specified key or value could not be
++     *         found
++     */
++    private V doRemoveByKey(final K key) {
++        Node<K, V> node = lookup(key, KEY);
++        V rval = null;
++        if (node != null) {
++            rval = node.getValue();
++            doRedBlackDelete(node);
++        }
++        return rval;
++    }
++
++    /**
++     * Remove by value
++     *
++     * @param value the value
++     * @return the key, if remove by value, or the value, if remove by
++     *         key. null if the specified key or value could not be
++     *         found
++     */
++    private K doRemoveByValue(final Comparable value) {
++        Node<K, V> node = lookup(value, VALUE);
++        K rval = null;
++        if (node != null) {
++            rval = node.getKey();
++            doRedBlackDelete(node);
++        }
++        return rval;
++    }
++
++    /**
++     * do the actual lookup of a piece of data
++     *
++     * @param data  the key or value to be looked up
++     * @param index the KEY or VALUE int
++     * @return the desired Node, or null if there is no mapping of the
++     *         specified data
++     */
++    private Node<K, V> lookup(final Comparable data, final int index) {
++        Node<K, V> rval = null;
++        Node<K, V> node = rootNode[index];
++
++        while (node != null) {
++            int cmp = compare(data, node.getData(index));
++            if (cmp == 0) {
++                rval = node;
++                break;
++            } else {
++                node = (cmp < 0) ? node.getLeft(index) : node.getRight(index);
++            }
++        }
++
++        return rval;
++    }
++
++    /**
++     * get the next larger node from the specified node
++     *
++     * @param node  the node to be searched from
++     * @param index the KEY or VALUE int
++     * @return the specified node
++     */
++    private Node<K, V> nextGreater(final Node<K, V> node, final int index) {
++        Node<K, V> rval = null;
++        if (node == null) {
++            rval = null;
++        } else if (node.getRight(index) != null) {
++            // everything to the node's right is larger. The least of
++            // the right node's descendants is the next larger node
++            rval = leastNode(node.getRight(index), index);
++        } else {
++            // traverse up our ancestry until we find an ancestor that
++            // is null or one whose left child is our ancestor. If we
++            // find a null, then this node IS the largest node in the
++            // tree, and there is no greater node. Otherwise, we are
++            // the largest node in the subtree on that ancestor's left
++            // ... and that ancestor is the next greatest node
++            Node<K, V> parent = node.getParent(index);
++            Node<K, V> child = node;
++
++            while ((parent != null) && (child == parent.getRight(index))) {
++                child = parent;
++                parent = parent.getParent(index);
++            }
++            rval = parent;
++        }
++        return rval;
++    }
++
++    /**
++     * get the next larger node from the specified node
++     *
++     * @param node  the node to be searched from
++     * @param index the KEY or VALUE int
++     * @return the specified node
++     */
++    private Node<K, V> nextSmaller(final Node<K, V> node, final int index) {
++        Node<K, V> rval = null;
++        if (node == null) {
++            rval = null;
++        } else if (node.getLeft(index) != null) {
++            // everything to the node's left is smaller. The greatest of
++            // the left node's descendants is the next smaller node
++            rval = greatestNode(node.getLeft(index), index);
++        } else {
++            // traverse up our ancestry until we find an ancestor that
++            // is null or one whose right child is our ancestor. If we
++            // find a null, then this node IS the largest node in the
++            // tree, and there is no greater node. Otherwise, we are
++            // the largest node in the subtree on that ancestor's right
++            // ... and that ancestor is the next greatest node
++            Node<K, V> parent = node.getParent(index);
++            Node<K, V> child = node;
++
++            while ((parent != null) && (child == parent.getLeft(index))) {
++                child = parent;
++                parent = parent.getParent(index);
++            }
++            rval = parent;
++        }
++        return rval;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Get the opposite index of the specified index
++     *
++     * @param index the KEY or VALUE int
++     * @return VALUE (if KEY was specified), else KEY
++     */
++    private static int oppositeIndex(final int index) {
++        // old trick ... to find the opposite of a value, m or n,
++        // subtract the value from the sum of the two possible
++        // values. (m + n) - m = n; (m + n) - n = m
++        return SUM_OF_INDICES - index;
++    }
++
++    /**
++     * Compare two objects
++     *
++     * @param o1 the first object
++     * @param o2 the second object
++     * @return negative value if o1 < o2; 0 if o1 == o2; positive
++     *         value if o1 > o2
++     */
++    private static int compare(final Comparable o1, final Comparable o2) {
++        return o1.compareTo(o2);
++    }
++
++    /**
++     * Find the least node from a given node.
++     *
++     * @param node  the node from which we will start searching
++     * @param index the KEY or VALUE int
++     * @return the smallest node, from the specified node, in the
++     *         specified mapping
++     */
++    private static <K extends Comparable,V extends Comparable> Node<K, V> leastNode(final Node<K, V> node, final int index) {
++        Node<K, V> rval = node;
++        if (rval != null) {
++            while (rval.getLeft(index) != null) {
++                rval = rval.getLeft(index);
++            }
++        }
++        return rval;
++    }
++
++    /**
++     * Find the greatest node from a given node.
++     *
++     * @param node  the node from which we will start searching
++     * @param index the KEY or VALUE int
++     * @return the greatest node, from the specified node
++     */
++    private static <K extends Comparable,V extends Comparable> Node<K, V> greatestNode(final Node<K, V> node, final int index) {
++        Node<K, V> rval = node;
++        if (rval != null) {
++            while (rval.getRight(index) != null) {
++                rval = rval.getRight(index);
++            }
++        }
++        return rval;
++    }
++
++    /**
++     * copy the color from one node to another, dealing with the fact
++     * that one or both nodes may, in fact, be null
++     *
++     * @param from  the node whose color we're copying; may be null
++     * @param to    the node whose color we're changing; may be null
++     * @param index the KEY or VALUE int
++     */
++    private static void copyColor(final Node from, final Node to, final int index) {
++        if (to != null) {
++            if (from == null) {
++                // by default, make it black
++                to.setBlack(index);
++            } else {
++                to.copyColor(from, index);
++            }
++        }
++    }
++
++    /**
++     * is the specified node red? if the node does not exist, no, it's
++     * black, thank you
++     *
++     * @param node  the node (may be null) in question
++     * @param index the KEY or VALUE int
++     */
++    private static boolean isRed(final Node node, final int index) {
++        return ((node == null) ? false : node.isRed(index));
++    }
++
++    /**
++     * is the specified black red? if the node does not exist, sure,
++     * it's black, thank you
++     *
++     * @param node  the node (may be null) in question
++     * @param index the KEY or VALUE int
++     */
++    private static boolean isBlack(final Node node, final int index) {
++        return ((node == null) ? true : node.isBlack(index));
++    }
++
++    /**
++     * force a node (if it exists) red
++     *
++     * @param node  the node (may be null) in question
++     * @param index the KEY or VALUE int
++     */
++    private static void makeRed(final Node node, final int index) {
++        if (node != null) {
++            node.setRed(index);
++        }
++    }
++
++    /**
++     * force a node (if it exists) black
++     *
++     * @param node  the node (may be null) in question
++     * @param index the KEY or VALUE int
++     */
++    private static <K extends Comparable,V extends Comparable> void makeBlack(final Node<K, V> node, final int index) {
++        if (node != null) {
++            node.setBlack(index);
++        }
++    }
++
++    /**
++     * get a node's grandparent. mind you, the node, its parent, or
++     * its grandparent may not exist. no problem
++     *
++     * @param node  the node (may be null) in question
++     * @param index the KEY or VALUE int
++     */
++    private static <K extends Comparable,V extends Comparable> Node<K, V> getGrandParent(final Node<K, V> node, final int index) {
++        return getParent(getParent(node, index), index);
++    }
++
++    /**
++     * get a node's parent. mind you, the node, or its parent, may not
++     * exist. no problem
++     *
++     * @param node  the node (may be null) in question
++     * @param index the KEY or VALUE int
++     */
++    private static <K extends Comparable,V extends Comparable> Node<K, V> getParent(final Node<K, V> node, final int index) {
++        return ((node == null) ? null : node.getParent(index));
++    }
++
++    /**
++     * get a node's right child. mind you, the node may not exist. no
++     * problem
++     *
++     * @param node  the node (may be null) in question
++     * @param index the KEY or VALUE int
++     */
++    private static <K extends Comparable,V extends Comparable> Node<K, V> getRightChild(final Node<K, V> node, final int index) {
++        return (node == null) ? null : node.getRight(index);
++    }
++
++    /**
++     * get a node's left child. mind you, the node may not exist. no
++     * problem
++     *
++     * @param node  the node (may be null) in question
++     * @param index the KEY or VALUE int
++     */
++    private static <K extends Comparable,V extends Comparable> Node<K, V> getLeftChild(final Node<K, V> node, final int index) {
++        return (node == null) ? null : node.getLeft(index);
++    }
++
++    /**
++     * is this node its parent's left child? mind you, the node, or
++     * its parent, may not exist. no problem. if the node doesn't
++     * exist ... it's its non-existent parent's left child. If the
++     * node does exist but has no parent ... no, we're not the
++     * non-existent parent's left child. Otherwise (both the specified
++     * node AND its parent exist), check.
++     *
++     * @param node  the node (may be null) in question
++     * @param index the KEY or VALUE int
++     */
++    private static <K extends Comparable,V extends Comparable> boolean isLeftChild(final Node<K, V> node, final int index) {
++        return (node == null) ? true : ((node.getParent(index) == null) ? false : (node == node.getParent(index).getLeft(index)));
++    }
++
++    /**
++     * is this node its parent's right child? mind you, the node, or
++     * its parent, may not exist. no problem. if the node doesn't
++     * exist ... it's its non-existent parent's right child. If the
++     * node does exist but has no parent ... no, we're not the
++     * non-existent parent's right child. Otherwise (both the
++     * specified node AND its parent exist), check.
++     *
++     * @param node  the node (may be null) in question
++     * @param index the KEY or VALUE int
++     */
++    private static <K extends Comparable,V extends Comparable> boolean isRightChild(final Node<K, V> node, final int index) {
++        return (node == null) ? true : ((node.getParent(index) == null) ? false : (node == node.getParent(index).getRight(index)));
++    }
++
++    /**
++     * do a rotate left. standard fare in the world of balanced trees
++     *
++     * @param node  the node to be rotated
++     * @param index the KEY or VALUE int
++     */
++    private void rotateLeft(final Node<K, V> node, final int index) {
++        Node<K, V> rightChild = node.getRight(index);
++        node.setRight(rightChild.getLeft(index), index);
++
++        if (rightChild.getLeft(index) != null) {
++            rightChild.getLeft(index).setParent(node, index);
++        }
++        rightChild.setParent(node.getParent(index), index);
++
++        if (node.getParent(index) == null) {
++            // node was the root ... now its right child is the root
++            rootNode[index] = rightChild;
++        } else if (node.getParent(index).getLeft(index) == node) {
++            node.getParent(index).setLeft(rightChild, index);
++        } else {
++            node.getParent(index).setRight(rightChild, index);
++        }
++
++        rightChild.setLeft(node, index);
++        node.setParent(rightChild, index);
++    }
++
++    /**
++     * do a rotate right. standard fare in the world of balanced trees
++     *
++     * @param node  the node to be rotated
++     * @param index the KEY or VALUE int
++     */
++    private void rotateRight(final Node<K, V> node, final int index) {
++        Node<K, V> leftChild = node.getLeft(index);
++        node.setLeft(leftChild.getRight(index), index);
++        if (leftChild.getRight(index) != null) {
++            leftChild.getRight(index).setParent(node, index);
++        }
++        leftChild.setParent(node.getParent(index), index);
++
++        if (node.getParent(index) == null) {
++            // node was the root ... now its left child is the root
++            rootNode[index] = leftChild;
++        } else if (node.getParent(index).getRight(index) == node) {
++            node.getParent(index).setRight(leftChild, index);
++        } else {
++            node.getParent(index).setLeft(leftChild, index);
++        }
++
++        leftChild.setRight(node, index);
++        node.setParent(leftChild, index);
++    }
++
++    /**
++     * complicated red-black insert stuff. Based on Sun's TreeMap
++     * implementation, though it's barely recognizable any more
++     *
++     * @param insertedNode the node to be inserted
++     * @param index        the KEY or VALUE int
++     */
++    private void doRedBlackInsert(final Node<K, V> insertedNode, final int index) {
++        Node<K, V> currentNode = insertedNode;
++        makeRed(currentNode, index);
++
++        while ((currentNode != null) && (currentNode != rootNode[index]) && (isRed(currentNode.getParent(index), index))) {
++            if (isLeftChild(getParent(currentNode, index), index)) {
++                Node<K, V> y = getRightChild(getGrandParent(currentNode, index), index);
++
++                if (isRed(y, index)) {
++                    makeBlack(getParent(currentNode, index), index);
++                    makeBlack(y, index);
++                    makeRed(getGrandParent(currentNode, index), index);
++
++                    currentNode = getGrandParent(currentNode, index);
++                } else {
++                    if (isRightChild(currentNode, index)) {
++                        currentNode = getParent(currentNode, index);
++
++                        rotateLeft(currentNode, index);
++                    }
++
++                    makeBlack(getParent(currentNode, index), index);
++                    makeRed(getGrandParent(currentNode, index), index);
++
++                    if (getGrandParent(currentNode, index) != null) {
++                        rotateRight(getGrandParent(currentNode, index), index);
++                    }
++                }
++            } else {
++
++                // just like clause above, except swap left for right
++                Node<K, V> y = getLeftChild(getGrandParent(currentNode, index), index);
++
++                if (isRed(y, index)) {
++                    makeBlack(getParent(currentNode, index), index);
++                    makeBlack(y, index);
++                    makeRed(getGrandParent(currentNode, index), index);
++
++                    currentNode = getGrandParent(currentNode, index);
++                } else {
++                    if (isLeftChild(currentNode, index)) {
++                        currentNode = getParent(currentNode, index);
++
++                        rotateRight(currentNode, index);
++                    }
++
++                    makeBlack(getParent(currentNode, index), index);
++                    makeRed(getGrandParent(currentNode, index), index);
++
++                    if (getGrandParent(currentNode, index) != null) {
++                        rotateLeft(getGrandParent(currentNode, index), index);
++                    }
++                }
++            }
++        }
++
++        makeBlack(rootNode[index], index);
++    }
++
++    /**
++     * complicated red-black delete stuff. Based on Sun's TreeMap
++     * implementation, though it's barely recognizable any more
++     *
++     * @param deletedNode the node to be deleted
++     */
++    private void doRedBlackDelete(final Node<K, V> deletedNode) {
++        for (int index = FIRST_INDEX; index < NUMBER_OF_INDICES; index++) {
++            // if deleted node has both left and children, swap with
++            // the next greater node
++            if ((deletedNode.getLeft(index) != null) && (deletedNode.getRight(index) != null)) {
++                swapPosition(nextGreater(deletedNode, index), deletedNode, index);
++            }
++
++            Node<K, V> replacement = ((deletedNode.getLeft(index) != null) ? deletedNode.getLeft(index) : deletedNode.getRight(index));
++
++            if (replacement != null) {
++                replacement.setParent(deletedNode.getParent(index), index);
++
++                if (deletedNode.getParent(index) == null) {
++                    rootNode[index] = replacement;
++                } else if (deletedNode == deletedNode.getParent(index).getLeft(index)) {
++                    deletedNode.getParent(index).setLeft(replacement, index);
++                } else {
++                    deletedNode.getParent(index).setRight(replacement, index);
++                }
++
++                deletedNode.setLeft(null, index);
++                deletedNode.setRight(null, index);
++                deletedNode.setParent(null, index);
++
++                if (isBlack(deletedNode, index)) {
++                    doRedBlackDeleteFixup(replacement, index);
++                }
++            } else {
++
++                // replacement is null
++                if (deletedNode.getParent(index) == null) {
++
++                    // empty tree
++                    rootNode[index] = null;
++                } else {
++
++                    // deleted node had no children
++                    if (isBlack(deletedNode, index)) {
++                        doRedBlackDeleteFixup(deletedNode, index);
++                    }
++
++                    if (deletedNode.getParent(index) != null) {
++                        if (deletedNode == deletedNode.getParent(index).getLeft(index)) {
++                            deletedNode.getParent(index).setLeft(null, index);
++                        } else {
++                            deletedNode.getParent(index).setRight(null, index);
++                        }
++
++                        deletedNode.setParent(null, index);
++                    }
++                }
++            }
++        }
++        shrink();
++    }
++
++    /**
++     * complicated red-black delete stuff. Based on Sun's TreeMap
++     * implementation, though it's barely recognizable any more. This
++     * rebalances the tree (somewhat, as red-black trees are not
++     * perfectly balanced -- perfect balancing takes longer)
++     *
++     * @param replacementNode the node being replaced
++     * @param index           the KEY or VALUE int
++     */
++    private void doRedBlackDeleteFixup(final Node<K, V> replacementNode, final int index) {
++        Node<K, V> currentNode = replacementNode;
++
++        while ((currentNode != rootNode[index]) && (isBlack(currentNode, index))) {
++            if (isLeftChild(currentNode, index)) {
++                Node<K, V> siblingNode = getRightChild(getParent(currentNode, index), index);
++
++                if (isRed(siblingNode, index)) {
++                    makeBlack(siblingNode, index);
++                    makeRed(getParent(currentNode, index), index);
++                    rotateLeft(getParent(currentNode, index), index);
++
++                    siblingNode = getRightChild(getParent(currentNode, index), index);
++                }
++
++                if (isBlack(getLeftChild(siblingNode, index), index) && isBlack(getRightChild(siblingNode, index), index)) {
++                    makeRed(siblingNode, index);
++
++                    currentNode = getParent(currentNode, index);
++                } else {
++                    if (isBlack(getRightChild(siblingNode, index), index)) {
++                        makeBlack(getLeftChild(siblingNode, index), index);
++                        makeRed(siblingNode, index);
++                        rotateRight(siblingNode, index);
++
++                        siblingNode = getRightChild(getParent(currentNode, index), index);
++                    }
++
++                    copyColor(getParent(currentNode, index), siblingNode, index);
++                    makeBlack(getParent(currentNode, index), index);
++                    makeBlack(getRightChild(siblingNode, index), index);
++                    rotateLeft(getParent(currentNode, index), index);
++
++                    currentNode = rootNode[index];
++                }
++            } else {
++                Node<K, V> siblingNode = getLeftChild(getParent(currentNode, index), index);
++
++                if (isRed(siblingNode, index)) {
++                    makeBlack(siblingNode, index);
++                    makeRed(getParent(currentNode, index), index);
++                    rotateRight(getParent(currentNode, index), index);
++
++                    siblingNode = getLeftChild(getParent(currentNode, index), index);
++                }
++
++                if (isBlack(getRightChild(siblingNode, index), index) && isBlack(getLeftChild(siblingNode, index), index)) {
++                    makeRed(siblingNode, index);
++
++                    currentNode = getParent(currentNode, index);
++                } else {
++                    if (isBlack(getLeftChild(siblingNode, index), index)) {
++                        makeBlack(getRightChild(siblingNode, index), index);
++                        makeRed(siblingNode, index);
++                        rotateLeft(siblingNode, index);
++
++                        siblingNode = getLeftChild(getParent(currentNode, index), index);
++                    }
++
++                    copyColor(getParent(currentNode, index), siblingNode, index);
++                    makeBlack(getParent(currentNode, index), index);
++                    makeBlack(getLeftChild(siblingNode, index), index);
++                    rotateRight(getParent(currentNode, index), index);
++
++                    currentNode = rootNode[index];
++                }
++            }
++        }
++
++        makeBlack(currentNode, index);
++    }
++
++    /**
++     * swap two nodes (except for their content), taking care of
++     * special cases where one is the other's parent ... hey, it
++     * happens.
++     *
++     * @param x     one node
++     * @param y     another node
++     * @param index the KEY or VALUE int
++     */
++    private void swapPosition(final Node<K, V> x, final Node<K, V> y, final int index) {
++        // Save initial values.
++        Node<K, V> xFormerParent = x.getParent(index);
++        Node<K, V> xFormerLeftChild = x.getLeft(index);
++        Node<K, V> xFormerRightChild = x.getRight(index);
++        Node<K, V> yFormerParent = y.getParent(index);
++        Node<K, V> yFormerLeftChild = y.getLeft(index);
++        Node<K, V> yFormerRightChild = y.getRight(index);
++        boolean xWasLeftChild = (x.getParent(index) != null) && (x == x.getParent(index).getLeft(index));
++        boolean yWasLeftChild = (y.getParent(index) != null) && (y == y.getParent(index).getLeft(index));
++
++        // Swap, handling special cases of one being the other's parent.
++        if (x == yFormerParent) { // x was y's parent
++            x.setParent(y, index);
++
++            if (yWasLeftChild) {
++                y.setLeft(x, index);
++                y.setRight(xFormerRightChild, index);
++            } else {
++                y.setRight(x, index);
++                y.setLeft(xFormerLeftChild, index);
++            }
++        } else {
++            x.setParent(yFormerParent, index);
++
++            if (yFormerParent != null) {
++                if (yWasLeftChild) {
++                    yFormerParent.setLeft(x, index);
++                } else {
++                    yFormerParent.setRight(x, index);
++                }
++            }
++
++            y.setLeft(xFormerLeftChild, index);
++            y.setRight(xFormerRightChild, index);
++        }
++
++        if (y == xFormerParent) { // y was x's parent
++            y.setParent(x, index);
++
++            if (xWasLeftChild) {
++                x.setLeft(y, index);
++                x.setRight(yFormerRightChild, index);
++            } else {
++                x.setRight(y, index);
++                x.setLeft(yFormerLeftChild, index);
++            }
++        } else {
++            y.setParent(xFormerParent, index);
++
++            if (xFormerParent != null) {
++                if (xWasLeftChild) {
++                    xFormerParent.setLeft(y, index);
++                } else {
++                    xFormerParent.setRight(y, index);
++                }
++            }
++
++            x.setLeft(yFormerLeftChild, index);
++            x.setRight(yFormerRightChild, index);
++        }
++
++        // Fix children's parent pointers
++        if (x.getLeft(index) != null) {
++            x.getLeft(index).setParent(x, index);
++        }
++
++        if (x.getRight(index) != null) {
++            x.getRight(index).setParent(x, index);
++        }
++
++        if (y.getLeft(index) != null) {
++            y.getLeft(index).setParent(y, index);
++        }
++
++        if (y.getRight(index) != null) {
++            y.getRight(index).setParent(y, index);
++        }
++
++        x.swapColors(y, index);
++
++        // Check if root changed
++        if (rootNode[index] == x) {
++            rootNode[index] = y;
++        } else if (rootNode[index] == y) {
++            rootNode[index] = x;
++        }
++    }
++
++    /**
++     * check if an object is fit to be proper input ... has to be
++     * Comparable and non-null
++     *
++     * @param o the object being checked
++     * @throws NullPointerException if o is null
++     * @throws ClassCastException   if o is not Comparable
++     */
++    private static void checkNonNullComparable(final Object o) {
++        if (o == null) {
++            throw new NullPointerException("Cannot be null");
++        }
++        if (!(o instanceof Comparable)) {
++            throw new ClassCastException("Must be Comparable");
++        }
++    }
++
++    /**
++     * check a key for validity (non-null and implements Comparable)
++     *
++     * @param key the key to be checked
++     * @throws NullPointerException if key is null
++     * @throws ClassCastException   if key is not Comparable
++     */
++    private static void checkKey(final Object key) {
++        checkNonNullComparable(key);
++    }
++
++    /**
++     * check a value for validity (non-null and implements Comparable)
++     *
++     * @param value the value to be checked
++     * @throws NullPointerException if value is null
++     * @throws ClassCastException   if value is not Comparable
++     */
++    private static void checkValue(final Object value) {
++        checkNonNullComparable(value);
++    }
++
++    /**
++     * check a key and a value for validity (non-null and implements
++     * Comparable)
++     *
++     * @param key   the key to be checked
++     * @param value the value to be checked
++     * @throws NullPointerException if key or value is null
++     * @throws ClassCastException   if key or value is not Comparable
++     */
++    private static void checkKeyAndValue(final Object key, final Object value) {
++        checkKey(key);
++        checkValue(value);
++    }
++
++    /**
++     * increment the modification count -- used to check for
++     * concurrent modification of the map through the map and through
++     * an Iterator from one of its Set or Collection views
++     */
++    private void modify() {
++        modifications++;
++    }
++
++    /**
++     * bump up the size and note that the map has changed
++     */
++    private void grow() {
++        modify();
++        nodeCount++;
++    }
++
++    /**
++     * decrement the size and note that the map has changed
++     */
++    private void shrink() {
++        modify();
++        nodeCount--;
++    }
++
++    /**
++     * insert a node by its value
++     *
++     * @param newNode the node to be inserted
++     * @throws IllegalArgumentException if the node already exists
++     *                                  in the value mapping
++     */
++    private void insertValue(final Node<K, V> newNode) throws IllegalArgumentException {
++        Node<K, V> node = rootNode[VALUE];
++
++        while (true) {
++            int cmp = compare(newNode.getData(VALUE), node.getData(VALUE));
++
++            if (cmp == 0) {
++                throw new IllegalArgumentException("Cannot store a duplicate value (\"" + newNode.getData(VALUE) + "\") in this Map");
++            } else if (cmp < 0) {
++                if (node.getLeft(VALUE) != null) {
++                    node = node.getLeft(VALUE);
++                } else {
++                    node.setLeft(newNode, VALUE);
++                    newNode.setParent(node, VALUE);
++                    doRedBlackInsert(newNode, VALUE);
++
++                    break;
++                }
++            } else { // cmp > 0
++                if (node.getRight(VALUE) != null) {
++                    node = node.getRight(VALUE);
++                } else {
++                    node.setRight(newNode, VALUE);
++                    newNode.setParent(node, VALUE);
++                    doRedBlackInsert(newNode, VALUE);
++
++                    break;
++                }
++            }
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Compares for equals as per the API.
++     *
++     * @param obj the object to compare to
++     * @return true if equal
++     */
++    private boolean doEquals(Object obj, final int type) {
++        if (obj == this) {
++            return true;
++        }
++        if (obj instanceof Map == false) {
++            return false;
++        }
++        Map other = (Map) obj;
++        if (other.size() != size()) {
++            return false;
++        }
++
++        if (nodeCount > 0) {
++            try {
++                for (MapIterator it = new ViewMapIterator(this, type); it.hasNext();) {
++                    Object key = it.next();
++                    Object value = it.getValue();
++                    if (value.equals(other.get(key)) == false) {
++                        return false;
++                    }
++                }
++            } catch (ClassCastException ex) {
++                return false;
++            } catch (NullPointerException ex) {
++                return false;
++            }
++        }
++        return true;
++    }
++
++    /**
++     * Gets the hash code value for this map as per the API.
++     *
++     * @return the hash code value for this map
++     */
++    private int doHashCode(final int type) {
++        int total = 0;
++        if (nodeCount > 0) {
++            for (MapIterator it = new ViewMapIterator(this, type); it.hasNext();) {
++                Object key = it.next();
++                Object value = it.getValue();
++                total += (key.hashCode() ^ value.hashCode());
++            }
++        }
++        return total;
++    }
++
++    /**
++     * Gets the string form of this map as per AbstractMap.
++     *
++     * @return the string form of this map
++     */
++    private String doToString(final int type) {
++        if (nodeCount == 0) {
++            return "{}";
++        }
++        StringBuffer buf = new StringBuffer(nodeCount * 32);
++        buf.append('{');
++        MapIterator it = new ViewMapIterator(this, type);
++        boolean hasNext = it.hasNext();
++        while (hasNext) {
++            Object key = it.next();
++            Object value = it.getValue();
++            buf.append(key == this ? "(this Map)" : key).append('=').append(value == this ? "(this Map)" : value);
++
++            hasNext = it.hasNext();
++            if (hasNext) {
++                buf.append(", ");
++            }
++        }
++
++        buf.append('}');
++        return buf.toString();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * A view of this map.
++     */
++    static class View <K extends Comparable,V extends Comparable> extends AbstractSet {
++
++        /**
++         * The parent map.
++         */
++        protected final TreeBidiMap main;
++        /**
++         * Whether to return KEY or VALUE order.
++         */
++        protected final int orderType;
++        /**
++         * Whether to return KEY, VALUE, MAPENTRY or INVERSEMAPENTRY data.
++         */
++        protected final int dataType;
++
++        /**
++         * Constructor.
++         *
++         * @param main      the main map
++         * @param orderType the KEY or VALUE int for the order
++         * @param dataType  the KEY, VALUE, MAPENTRY or INVERSEMAPENTRY int
++         */
++        View(final TreeBidiMap main, final int orderType, final int dataType) {
++            super();
++            this.main = main;
++            this.orderType = orderType;
++            this.dataType = dataType;
++        }
++
++        public Iterator iterator() {
++            return new ViewIterator(main, orderType, dataType);
++        }
++
++        public int size() {
++            return main.size();
++        }
++
++        public boolean contains(final Object obj) {
++            checkNonNullComparable(obj);
++            return (main.lookup((Comparable) obj, dataType) != null);
++        }
++
++        public boolean remove(final Object obj) {
++            if (dataType == KEY) {
++                return main.doRemoveByKey((K) obj) != null;
++            } else {
++                return main.doRemoveByValue((V) obj) != null;
++            }
++        }
++
++        public void clear() {
++            main.clear();
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * An iterator over the map.
++     */
++    static class ViewIterator implements OrderedIterator {
++
++        /**
++         * The parent map.
++         */
++        protected final TreeBidiMap main;
++        /**
++         * Whether to return KEY or VALUE order.
++         */
++        protected final int orderType;
++        /**
++         * Whether to return KEY, VALUE, MAPENTRY or INVERSEMAPENTRY data.
++         */
++        protected final int dataType;
++        /**
++         * The last node returned by the iterator.
++         */
++        protected Node lastReturnedNode;
++        /**
++         * The next node to be returned by the iterator.
++         */
++        protected Node nextNode;
++        /**
++         * The previous node in the sequence returned by the iterator.
++         */
++        protected Node previousNode;
++        /**
++         * The modification count.
++         */
++        private int expectedModifications;
++
++        /**
++         * Constructor.
++         *
++         * @param main      the main map
++         * @param orderType the KEY or VALUE int for the order
++         * @param dataType  the KEY, VALUE, MAPENTRY or INVERSEMAPENTRY int
++         */
++        ViewIterator(final TreeBidiMap main, final int orderType, final int dataType) {
++            super();
++            this.main = main;
++            this.orderType = orderType;
++            this.dataType = dataType;
++            expectedModifications = main.modifications;
++            nextNode = leastNode(main.rootNode[orderType], orderType);
++            lastReturnedNode = null;
++            previousNode = null;
++        }
++
++        public final boolean hasNext() {
++            return (nextNode != null);
++        }
++
++        public final Object next() {
++            if (nextNode == null) {
++                throw new NoSuchElementException();
++            }
++            if (main.modifications != expectedModifications) {
++                throw new ConcurrentModificationException();
++            }
++            lastReturnedNode = nextNode;
++            previousNode = nextNode;
++            nextNode = main.nextGreater(nextNode, orderType);
++            return doGetData();
++        }
++
++        public boolean hasPrevious() {
++            return (previousNode != null);
++        }
++
++        public Object previous() {
++            if (previousNode == null) {
++                throw new NoSuchElementException();
++            }
++            if (main.modifications != expectedModifications) {
++                throw new ConcurrentModificationException();
++            }
++            nextNode = lastReturnedNode;
++            if (nextNode == null) {
++                nextNode = main.nextGreater(previousNode, orderType);
++            }
++            lastReturnedNode = previousNode;
++            previousNode = main.nextSmaller(previousNode, orderType);
++            return doGetData();
++        }
++
++        /**
++         * Gets the data value for the lastReturnedNode field.
++         *
++         * @return the data value
++         */
++        protected Object doGetData() {
++            switch (dataType) {
++                case KEY:
++                    return lastReturnedNode.getKey();
++                case VALUE:
++                    return lastReturnedNode.getValue();
++                case MAPENTRY:
++                    return lastReturnedNode;
++                case INVERSEMAPENTRY:
++                    return new UnmodifiableMapEntry(lastReturnedNode.getValue(), lastReturnedNode.getKey());
++            }
++            return null;
++        }
++
++        public final void remove() {
++            if (lastReturnedNode == null) {
++                throw new IllegalStateException();
++            }
++            if (main.modifications != expectedModifications) {
++                throw new ConcurrentModificationException();
++            }
++            main.doRedBlackDelete(lastReturnedNode);
++            expectedModifications++;
++            lastReturnedNode = null;
++            if (nextNode == null) {
++                previousNode = main.greatestNode(main.rootNode[orderType], orderType);
++            } else {
++                previousNode = main.nextSmaller(nextNode, orderType);
++            }
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * An iterator over the map.
++     */
++    static class ViewMapIterator extends ViewIterator implements OrderedMapIterator {
++
++        private final int oppositeType;
++
++        /**
++         * Constructor.
++         *
++         * @param main      the main map
++         * @param orderType the KEY or VALUE int for the order
++         */
++        ViewMapIterator(final TreeBidiMap main, final int orderType) {
++            super(main, orderType, orderType);
++            this.oppositeType = oppositeIndex(dataType);
++        }
++
++        public Object getKey() {
++            if (lastReturnedNode == null) {
++                throw new IllegalStateException("Iterator getKey() can only be called after next() and before remove()");
++            }
++            return lastReturnedNode.getData(dataType);
++        }
++
++        public Object getValue() {
++            if (lastReturnedNode == null) {
++                throw new IllegalStateException("Iterator getValue() can only be called after next() and before remove()");
++            }
++            return lastReturnedNode.getData(oppositeType);
++        }
++
++        public Object setValue(final Object obj) {
++            throw new UnsupportedOperationException();
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * A view of this map.
++     */
++    static class EntryView extends View {
++
++        private final int oppositeType;
++
++        /**
++         * Constructor.
++         *
++         * @param main      the main map
++         * @param orderType the KEY or VALUE int for the order
++         * @param dataType  the MAPENTRY or INVERSEMAPENTRY int for the returned data
++         */
++        EntryView(final TreeBidiMap main, final int orderType, final int dataType) {
++            super(main, orderType, dataType);
++            this.oppositeType = main.oppositeIndex(orderType);
++        }
++
++        public boolean contains(Object obj) {
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++            Map.Entry entry = (Map.Entry) obj;
++            Object value = entry.getValue();
++            Node node = main.lookup((Comparable) entry.getKey(), orderType);
++            return (node != null && node.getData(oppositeType).equals(value));
++        }
++
++        public boolean remove(Object obj) {
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++            Map.Entry entry = (Map.Entry) obj;
++            Object value = entry.getValue();
++            Node node = main.lookup((Comparable) entry.getKey(), orderType);
++            if (node != null && node.getData(oppositeType).equals(value)) {
++                main.doRedBlackDelete(node);
++                return true;
++            }
++            return false;
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * A node used to store the data.
++     */
++    static class Node <K extends Comparable,V extends Comparable> implements Map.Entry<K, V>, KeyValue<K, V> {
++
++        private K key;
++        private V value;
++        private Node<K, V>[] leftNode;
++        private Node<K, V>[] rightNode;
++        private Node<K, V>[] parentNode;
++        private boolean[] blackColor;
++        private int hashcodeValue;
++        private boolean calculatedHashCode;
++
++        /**
++         * Make a new cell with given key and value, and with null
++         * links, and black (true) colors.
++         *
++         * @param key
++         * @param value
++         */
++        Node(final K key, final V value) {
++            super();
++            this.key = key;
++            this.value = value;
++            leftNode = new Node[2];
++            rightNode = new Node[2];
++            parentNode = new Node[2];
++            blackColor = new boolean[]{true, true};
++            calculatedHashCode = false;
++        }
++
++        /**
++         * Get the specified data.
++         *
++         * @param index the KEY or VALUE int
++         * @return the key or value
++         */
++        private Comparable getData(final int index) {
++            if (index == KEY) {
++                return key;
++            } else {
++                return value;
++            }
++        }
++
++        /**
++         * Set this node's left node.
++         *
++         * @param node  the new left node
++         * @param index the KEY or VALUE int
++         */
++        private void setLeft(final Node<K, V> node, final int index) {
++            leftNode[index] = node;
++        }
++
++        /**
++         * Get the left node.
++         *
++         * @param index the KEY or VALUE int
++         * @return the left node, may be null
++         */
++        private Node<K, V> getLeft(final int index) {
++            return leftNode[index];
++        }
++
++        /**
++         * Set this node's right node.
++         *
++         * @param node  the new right node
++         * @param index the KEY or VALUE int
++         */
++        private void setRight(final Node<K, V> node, final int index) {
++            rightNode[index] = node;
++        }
++
++        /**
++         * Get the right node.
++         *
++         * @param index the KEY or VALUE int
++         * @return the right node, may be null
++         */
++        private Node<K, V> getRight(final int index) {
++            return rightNode[index];
++        }
++
++        /**
++         * Set this node's parent node.
++         *
++         * @param node  the new parent node
++         * @param index the KEY or VALUE int
++         */
++        private void setParent(final Node<K, V> node, final int index) {
++            parentNode[index] = node;
++        }
++
++        /**
++         * Get the parent node.
++         *
++         * @param index the KEY or VALUE int
++         * @return the parent node, may be null
++         */
++        private Node<K, V> getParent(final int index) {
++            return parentNode[index];
++        }
++
++        /**
++         * Exchange colors with another node.
++         *
++         * @param node  the node to swap with
++         * @param index the KEY or VALUE int
++         */
++        private void swapColors(final Node<K, V> node, final int index) {
++            // Swap colors -- old hacker's trick
++            blackColor[index] ^= node.blackColor[index];
++            node.blackColor[index] ^= blackColor[index];
++            blackColor[index] ^= node.blackColor[index];
++        }
++
++        /**
++         * Is this node black?
++         *
++         * @param index the KEY or VALUE int
++         * @return true if black (which is represented as a true boolean)
++         */
++        private boolean isBlack(final int index) {
++            return blackColor[index];
++        }
++
++        /**
++         * Is this node red?
++         *
++         * @param index the KEY or VALUE int
++         * @return true if non-black
++         */
++        private boolean isRed(final int index) {
++            return !blackColor[index];
++        }
++
++        /**
++         * Make this node black.
++         *
++         * @param index the KEY or VALUE int
++         */
++        private void setBlack(final int index) {
++            blackColor[index] = true;
++        }
++
++        /**
++         * Make this node red.
++         *
++         * @param index the KEY or VALUE int
++         */
++        private void setRed(final int index) {
++            blackColor[index] = false;
++        }
++
++        /**
++         * Make this node the same color as another
++         *
++         * @param node  the node whose color we're adopting
++         * @param index the KEY or VALUE int
++         */
++        private void copyColor(final Node<K, V> node, final int index) {
++            blackColor[index] = node.blackColor[index];
++        }
++
++        //-------------------------------------------------------------------
++        /**
++         * Gets the key.
++         *
++         * @return the key corresponding to this entry.
++         */
++        public K getKey() {
++            return key;
++        }
++
++        /**
++         * Gets the value.
++         *
++         * @return the value corresponding to this entry.
++         */
++        public V getValue() {
++            return value;
++        }
++
++        /**
++         * Optional operation that is not permitted in this implementation
++         *
++         * @param ignored
++         * @return does not return
++         * @throws UnsupportedOperationException always
++         */
++        public V setValue(final V ignored) throws UnsupportedOperationException {
++            throw new UnsupportedOperationException("Map.Entry.setValue is not supported");
++        }
++
++        /**
++         * Compares the specified object with this entry for equality.
++         * Returns true if the given object is also a map entry and
++         * the two entries represent the same mapping.
++         *
++         * @param obj the object to be compared for equality with this entry.
++         * @return true if the specified object is equal to this entry.
++         */
++        public boolean equals(final Object obj) {
++            if (obj == this) {
++                return true;
++            }
++            if (!(obj instanceof Map.Entry)) {
++                return false;
++            }
++            Map.Entry e = (Map.Entry) obj;
++            return key.equals(e.getKey()) && value.equals(e.getValue());
++        }
++
++        /**
++         * @return the hash code value for this map entry.
++         */
++        public int hashCode() {
++            if (!calculatedHashCode) {
++                hashcodeValue = key.hashCode() ^ value.hashCode();
++                calculatedHashCode = true;
++            }
++            return hashcodeValue;
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * A node used to store the data.
++     */
++    static class Inverse <K extends Comparable,V extends Comparable> implements OrderedBidiMap<V, K> {
++
++        /**
++         * The parent map.
++         */
++        private final TreeBidiMap<K, V> main;
++        /**
++         * Store the keySet once created.
++         */
++        private Set keySet;
++        /**
++         * Store the valuesSet once created.
++         */
++        private Set valuesSet;
++        /**
++         * Store the entrySet once created.
++         */
++        private Set entrySet;
++
++        /**
++         * Constructor.
++         *
++         * @param main the main map
++         */
++        Inverse(final TreeBidiMap<K, V> main) {
++            super();
++            this.main = main;
++        }
++
++        public int size() {
++            return main.size();
++        }
++
++        public boolean isEmpty() {
++            return main.isEmpty();
++        }
++
++        public K get(final Object key) {
++            return main.getKey((V) key);
++        }
++
++        public V getKey(final Object value) {
++            return main.get(value);
++        }
++
++        public boolean containsKey(final Object key) {
++            return main.containsValue(key);
++        }
++
++        public boolean containsValue(final Object value) {
++            return main.containsKey(value);
++        }
++
++        public V firstKey() {
++            if (main.nodeCount == 0) {
++                throw new NoSuchElementException("Map is empty");
++            }
++            return main.leastNode(main.rootNode[VALUE], VALUE).getValue();
++        }
++
++        public V lastKey() {
++            if (main.nodeCount == 0) {
++                throw new NoSuchElementException("Map is empty");
++            }
++            return main.greatestNode(main.rootNode[VALUE], VALUE).getValue();
++        }
++
++        public V nextKey(V key) {
++            checkKey(key);
++            Node<K, V> node = main.nextGreater(main.lookup((Comparable) key, VALUE), VALUE);
++            return (node == null ? null : node.getValue());
++        }
++
++        public V previousKey(V key) {
++            checkKey(key);
++            Node<K, V> node = main.nextSmaller(main.lookup((Comparable) key, VALUE), VALUE);
++            return (node == null ? null : node.getValue());
++        }
++
++        public K put(final V key, final K value) {
++            return main.doPutByValue(value, key);
++        }
++
++        public void putAll(Map<? extends V, ? extends K> map) {
++            Iterator it = map.entrySet().iterator();
++            while (it.hasNext()) {
++                Map.Entry entry = (Map.Entry) it.next();
++                put((V) entry.getKey(), (K) entry.getValue());
++            }
++        }
++
++        public K remove(final Object key) {
++            return main.removeValue((V) key);
++        }
++
++        public V removeValue(final Object value) {
++            return main.remove(value);
++        }
++
++        public void clear() {
++            main.clear();
++        }
++
++        public Set<V> keySet() {
++            if (keySet == null) {
++                keySet = new View(main, VALUE, VALUE);
++            }
++            return keySet;
++        }
++
++        public Set<K> values() {
++            if (valuesSet == null) {
++                valuesSet = new View(main, VALUE, KEY);
++            }
++            return valuesSet;
++        }
++
++        public Set<Map.Entry<V, K>> entrySet() {
++            if (entrySet == null) {
++                return new EntryView(main, VALUE, INVERSEMAPENTRY);
++            }
++            return entrySet;
++        }
++
++        public MapIterator<V, K> mapIterator() {
++            if (isEmpty()) {
++                return EmptyOrderedMapIterator.INSTANCE;
++            }
++            return new ViewMapIterator(main, VALUE);
++        }
++
++        public OrderedMapIterator<V, K> orderedMapIterator() {
++            if (isEmpty()) {
++                return EmptyOrderedMapIterator.INSTANCE;
++            }
++            return new ViewMapIterator(main, VALUE);
++        }
++
++        public BidiMap<K, V> inverseBidiMap() {
++            return main;
++        }
++
++        public OrderedBidiMap<K, V> inverseOrderedBidiMap() {
++            return main;
++        }
++
++        public boolean equals(Object obj) {
++            return main.doEquals(obj, VALUE);
++        }
++
++        public int hashCode() {
++            return main.doHashCode(VALUE);
++        }
++
++        public String toString() {
++            return main.doToString(VALUE);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bidimap/UnmodifiableBidiMap.java
+@@ -0,0 +1,120 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bidimap;
++
++import org.apache.commons.collections15.BidiMap;
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.iterators.UnmodifiableMapIterator;
++import org.apache.commons.collections15.map.UnmodifiableEntrySet;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * Decorates another <code>BidiMap</code> to ensure it can't be altered.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableBidiMap <K,V> extends AbstractBidiMapDecorator<K, V> implements Unmodifiable {
++
++    /**
++     * The inverse unmodifiable map
++     */
++    private UnmodifiableBidiMap<V, K> inverse;
++
++    /**
++     * Factory method to create an unmodifiable map.
++     * <p/>
++     * If the map passed in is already unmodifiable, it is returned.
++     *
++     * @param map the map to decorate, must not be null
++     * @return an unmodifiable BidiMap
++     * @throws IllegalArgumentException if map is null
++     */
++    public static <K,V> BidiMap<K, V> decorate(BidiMap<K, V> map) {
++        if (map instanceof Unmodifiable) {
++            return map;
++        }
++        return new UnmodifiableBidiMap<K, V>(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    private UnmodifiableBidiMap(BidiMap<K, V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public V put(K key, V value) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void putAll(Map<? extends K, ? extends V> mapToCopy) {
++        throw new UnsupportedOperationException();
++    }
++
++    public V remove(Object key) {
++        throw new UnsupportedOperationException();
++    }
++
++    public Set<Map.Entry<K, V>> entrySet() {
++        Set<Map.Entry<K, V>> set = super.entrySet();
++        return UnmodifiableEntrySet.decorate(set);
++    }
++
++    public Set<K> keySet() {
++        Set<K> set = super.keySet();
++        return UnmodifiableSet.decorate(set);
++    }
++
++    public Set<V> values() {
++        Set<V> coll = super.values();
++        return (Set<V>) UnmodifiableSet.decorate(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    public K removeValue(Object value) {
++        throw new UnsupportedOperationException();
++    }
++
++    public MapIterator<K, V> mapIterator() {
++        MapIterator<K, V> it = getBidiMap().mapIterator();
++        return UnmodifiableMapIterator.decorate(it);
++    }
++
++    public BidiMap<V, K> inverseBidiMap() {
++        if (inverse == null) {
++            inverse = new UnmodifiableBidiMap<V, K>(getBidiMap().inverseBidiMap());
++            inverse.inverse = this;
++        }
++        return inverse;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bidimap/UnmodifiableOrderedBidiMap.java
+@@ -0,0 +1,127 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bidimap;
++
++import org.apache.commons.collections15.*;
++import org.apache.commons.collections15.iterators.UnmodifiableOrderedMapIterator;
++import org.apache.commons.collections15.map.UnmodifiableEntrySet;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * Decorates another <code>OrderedBidiMap</code> to ensure it can't be altered.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableOrderedBidiMap <K,V> extends AbstractOrderedBidiMapDecorator<K, V> implements Unmodifiable {
++
++    /**
++     * The inverse unmodifiable map
++     */
++    private UnmodifiableOrderedBidiMap<V, K> inverse;
++
++    /**
++     * Factory method to create an unmodifiable map.
++     * <p/>
++     * If the map passed in is already unmodifiable, it is returned.
++     *
++     * @param map the map to decorate, must not be null
++     * @return an unmodifiable OrderedBidiMap
++     * @throws IllegalArgumentException if map is null
++     */
++    public static <K,V> OrderedBidiMap<K, V> decorate(OrderedBidiMap<K, V> map) {
++        if (map instanceof Unmodifiable) {
++            return map;
++        }
++        return new UnmodifiableOrderedBidiMap<K, V>(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    private UnmodifiableOrderedBidiMap(OrderedBidiMap<K, V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public V put(K key, V value) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void putAll(Map<? extends K, ? extends V> mapToCopy) {
++        throw new UnsupportedOperationException();
++    }
++
++    public V remove(Object key) {
++        throw new UnsupportedOperationException();
++    }
++
++    public Set<Map.Entry<K, V>> entrySet() {
++        Set<Map.Entry<K, V>> set = super.entrySet();
++        return UnmodifiableEntrySet.decorate(set);
++    }
++
++    public Set<K> keySet() {
++        Set<K> set = super.keySet();
++        return UnmodifiableSet.decorate(set);
++    }
++
++    public Set<V> values() {
++        Set<V> coll = super.values();
++        return UnmodifiableSet.decorate(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    public K removeValue(Object value) {
++        throw new UnsupportedOperationException();
++    }
++
++    public MapIterator<K, V> mapIterator() {
++        return orderedMapIterator();
++    }
++
++    public BidiMap<V, K> inverseBidiMap() {
++        return inverseOrderedBidiMap();
++    }
++
++    //-----------------------------------------------------------------------
++    public OrderedMapIterator<K, V> orderedMapIterator() {
++        OrderedMapIterator<K, V> it = getOrderedBidiMap().orderedMapIterator();
++        return UnmodifiableOrderedMapIterator.decorate(it);
++    }
++
++    public OrderedBidiMap<V, K> inverseOrderedBidiMap() {
++        if (inverse == null) {
++            inverse = new UnmodifiableOrderedBidiMap<V, K>(getOrderedBidiMap().inverseOrderedBidiMap());
++            inverse.inverse = this;
++        }
++        return inverse;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bidimap/UnmodifiableSortedBidiMap.java
+@@ -0,0 +1,149 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.bidimap;
++
++import org.apache.commons.collections15.*;
++import org.apache.commons.collections15.iterators.UnmodifiableOrderedMapIterator;
++import org.apache.commons.collections15.map.UnmodifiableEntrySet;
++import org.apache.commons.collections15.map.UnmodifiableSortedMap;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.util.Map;
++import java.util.Set;
++import java.util.SortedMap;
++
++/**
++ * Decorates another <code>SortedBidiMap</code> to ensure it can't be altered.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:19 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableSortedBidiMap <K,V> extends AbstractSortedBidiMapDecorator<K, V> implements Unmodifiable {
++
++    /**
++     * The inverse unmodifiable map
++     */
++    private UnmodifiableSortedBidiMap<V, K> inverse;
++
++    /**
++     * Factory method to create an unmodifiable map.
++     * <p/>
++     * If the map passed in is already unmodifiable, it is returned.
++     *
++     * @param map the map to decorate, must not be null
++     * @return an unmodifiable SortedBidiMap
++     * @throws IllegalArgumentException if map is null
++     */
++    public static <K,V> SortedBidiMap<K, V> decorate(SortedBidiMap<K, V> map) {
++        if (map instanceof Unmodifiable) {
++            return map;
++        }
++        return new UnmodifiableSortedBidiMap<K, V>(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    private UnmodifiableSortedBidiMap(SortedBidiMap<K, V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public V put(K key, V value) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void putAll(Map<? extends K, ? extends V> mapToCopy) {
++        throw new UnsupportedOperationException();
++    }
++
++    public V remove(Object key) {
++        throw new UnsupportedOperationException();
++    }
++
++    public Set<Map.Entry<K, V>> entrySet() {
++        Set<Map.Entry<K, V>> set = super.entrySet();
++        return UnmodifiableEntrySet.decorate(set);
++    }
++
++    public Set<K> keySet() {
++        Set<K> set = super.keySet();
++        return UnmodifiableSet.decorate(set);
++    }
++
++    public Set<V> values() {
++        Set<V> coll = super.values();
++        return UnmodifiableSet.decorate(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    public K removeValue(Object value) {
++        throw new UnsupportedOperationException();
++    }
++
++    public MapIterator<K, V> mapIterator() {
++        return orderedMapIterator();
++    }
++
++    public BidiMap<V, K> inverseBidiMap() {
++        return inverseSortedBidiMap();
++    }
++
++    //-----------------------------------------------------------------------
++    public OrderedMapIterator<K, V> orderedMapIterator() {
++        OrderedMapIterator<K, V> it = getSortedBidiMap().orderedMapIterator();
++        return UnmodifiableOrderedMapIterator.decorate(it);
++    }
++
++    public OrderedBidiMap<V, K> inverseOrderedBidiMap() {
++        return inverseSortedBidiMap();
++    }
++
++    //-----------------------------------------------------------------------
++    public SortedBidiMap<V, K> inverseSortedBidiMap() {
++        if (inverse == null) {
++            inverse = new UnmodifiableSortedBidiMap<V, K>(getSortedBidiMap().inverseSortedBidiMap());
++            inverse.inverse = this;
++        }
++        return inverse;
++    }
++
++    public SortedMap<K, V> subMap(K fromKey, K toKey) {
++        SortedMap<K, V> sm = getSortedBidiMap().subMap(fromKey, toKey);
++        return UnmodifiableSortedMap.decorate(sm);
++    }
++
++    public SortedMap<K, V> headMap(K toKey) {
++        SortedMap<K, V> sm = getSortedBidiMap().headMap(toKey);
++        return UnmodifiableSortedMap.decorate(sm);
++    }
++
++    public SortedMap<K, V> tailMap(K fromKey) {
++        SortedMap<K, V> sm = getSortedBidiMap().tailMap(fromKey);
++        return UnmodifiableSortedMap.decorate(sm);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/bidimap/package.html
+@@ -0,0 +1,47 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:19 pents90 Exp $ -->
++ <!--
++   Copyright 2003-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<BODY>
++<p>
++This package contains implementations of the
++{@link org.apache.commons.collections.BidiMap BidiMap},
++{@link org.apache.commons.collections.OrderedBidiMap OrderedBidiMap} and 
++{@link org.apache.commons.collections.SortedBidiMap SortedBidiMap} interfaces.
++A BidiMap is an extension to Map that allows keys and values to be looked up with equal ease.
++One example usage is a system communicating to a legacy datasource that must convert codes
++from the new format to the old format and vice versa.
++<p>
++The following implementations are provided in the package:
++<ul>
++<li>DualHashBidiMap - uses two HashMaps to implement BidiMap
++<li>DualTreeBidiMap - uses two TreeMaps to implement SortedBidiMap
++<li>TreeBidiMap - red-black tree implementation of OrderedBidiMap
++</ul>
++<p>
++The following decorators are provided in the package:
++<ul>
++<li>Unmodifiable - ensures the map cannot be altered
++<!--
++<li>Synchronized - synchronizes method access for multi-threaded environments
++<li>Predicated - ensures that only elements that are valid according to a predicate can be added
++<li>Typed - ensures that only elements that are of a specific type can be added
++<li>Transformed - transforms each element added
++<li>FixedSize - ensures that the size of the map cannot change
++<li>Lazy - creates objects in the map on demand
++<li>ListOrdered - ensures that insertion order is retained-->
++</ul>
++</pre>
++</BODY>
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/AbstractBufferDecorator.java
+@@ -0,0 +1,70 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.buffer;
++
++import org.apache.commons.collections15.Buffer;
++import org.apache.commons.collections15.collection.AbstractCollectionDecorator;
++
++/**
++ * Decorates another <code>Buffer</code> to provide additional behaviour.
++ * <p/>
++ * Methods are forwarded directly to the decorated buffer.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractBufferDecorator <E> extends AbstractCollectionDecorator<E> implements Buffer<E> {
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     *
++     * @since Commons Collections 3.1
++     */
++    protected AbstractBufferDecorator() {
++        super();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param buffer the buffer to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    protected AbstractBufferDecorator(Buffer<E> buffer) {
++        super(buffer);
++    }
++
++    /**
++     * Gets the buffer being decorated.
++     *
++     * @return the decorated buffer
++     */
++    protected Buffer<E> getBuffer() {
++        return (Buffer<E>) getCollection();
++    }
++
++    //-----------------------------------------------------------------------
++    public E get() {
++        return getBuffer().get();
++    }
++
++    public E remove() {
++        return getBuffer().remove();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/BlockingBuffer.java
+@@ -0,0 +1,118 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.buffer;
++
++import org.apache.commons.collections15.Buffer;
++import org.apache.commons.collections15.BufferUnderflowException;
++
++import java.util.Collection;
++
++/**
++ * Decorates another <code>Buffer</code> to make {@link #get()} and
++ * {@link #remove()} block when the <code>Buffer</code> is empty.
++ * <p/>
++ * If either <code>get</code> or <code>remove</code> is called on an empty
++ * <code>Buffer</code>, the calling thread waits for notification that
++ * an <code>add</code> or <code>addAll</code> operation has completed.
++ * <p/>
++ * When one or more entries are added to an empty <code>Buffer</code>,
++ * all threads blocked in <code>get</code> or <code>remove</code> are notified.
++ * There is no guarantee that concurrent blocked <code>get</code> or
++ * <code>remove</code> requests will be "unblocked" and receive data in the
++ * order that they arrive.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Janek Bogucki
++ * @author Matt Hall, John Watkinson, Phil Steitz
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public class BlockingBuffer <E> extends SynchronizedBuffer<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 1719328905017860541L;
++
++    /**
++     * Factory method to create a blocking buffer.
++     *
++     * @param buffer the buffer to decorate, must not be null
++     * @return a new blocking Buffer
++     * @throws IllegalArgumentException if buffer is null
++     */
++    public static <E> Buffer<E> decorate(Buffer<E> buffer) {
++        return new BlockingBuffer<E>(buffer);
++    }
++
++    //-----------------------------------------------------------------------    
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param buffer the buffer to decorate, must not be null
++     * @throws IllegalArgumentException if the buffer is null
++     */
++    protected BlockingBuffer(Buffer<E> buffer) {
++        super(buffer);
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(E o) {
++        synchronized (lock) {
++            boolean result = collection.add(o);
++            notifyAll();
++            return result;
++        }
++    }
++
++    public boolean addAll(Collection<? extends E> c) {
++        synchronized (lock) {
++            boolean result = collection.addAll(c);
++            notifyAll();
++            return result;
++        }
++    }
++
++    public E get() {
++        synchronized (lock) {
++            while (collection.isEmpty()) {
++                try {
++                    wait();
++                } catch (InterruptedException e) {
++                    throw new BufferUnderflowException();
++                }
++            }
++            return getBuffer().get();
++        }
++    }
++
++    public E remove() {
++        synchronized (lock) {
++            while (collection.isEmpty()) {
++                try {
++                    wait();
++                } catch (InterruptedException e) {
++                    throw new BufferUnderflowException();
++                }
++            }
++            return getBuffer().remove();
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/BoundedFifoBuffer.java
+@@ -0,0 +1,363 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.buffer;
++
++import org.apache.commons.collections15.BoundedCollection;
++import org.apache.commons.collections15.Buffer;
++import org.apache.commons.collections15.BufferOverflowException;
++import org.apache.commons.collections15.BufferUnderflowException;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.*;
++
++/**
++ * The BoundedFifoBuffer is a very efficient implementation of
++ * Buffer that does not alter the size of the buffer at runtime.
++ * <p/>
++ * The removal order of a <code>BoundedFifoBuffer</code> is based on the
++ * insertion order; elements are removed in the same order in which they
++ * were added.  The iteration order is the same as the removal order.
++ * <p/>
++ * The {@link #add(Object)}, {@link #remove()} and {@link #get()} operations
++ * all perform in constant time.  All other operations perform in linear
++ * time or worse.
++ * <p/>
++ * Note that this implementation is not synchronized.  The following can be
++ * used to provide synchronized access to your <code>BoundedFifoBuffer</code>:
++ * <pre>
++ *   Buffer fifo = BufferUtils.synchronizedBuffer(new BoundedFifoBuffer());
++ * </pre>
++ * <p/>
++ * This buffer prevents null objects from being added.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Avalon
++ * @author Berin Loritsch
++ * @author Paul Jack
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Herve Quiroz
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0 (previously in main package v2.1)
++ */
++public class BoundedFifoBuffer <E> extends AbstractCollection<E> implements Buffer<E>, BoundedCollection<E>, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 5603722811189451017L;
++
++    private transient E[] elements;
++    private transient int start = 0;
++    private transient int end = 0;
++    private transient boolean full = false;
++    private final int maxElements;
++
++    /**
++     * Constructs a new <code>BoundedFifoBuffer</code> big enough to hold
++     * 32 elements.
++     */
++    public BoundedFifoBuffer() {
++        this(32);
++    }
++
++    /**
++     * Constructs a new <code>BoundedFifoBuffer</code> big enough to hold
++     * the specified number of elements.
++     *
++     * @param size the maximum number of elements for this fifo
++     * @throws IllegalArgumentException if the size is less than 1
++     */
++    public BoundedFifoBuffer(int size) {
++        if (size <= 0) {
++            throw new IllegalArgumentException("The size must be greater than 0");
++        }
++        elements = (E[]) new Object[size];
++        maxElements = elements.length;
++    }
++
++    /**
++     * Constructs a new <code>BoundedFifoBuffer</code> big enough to hold all
++     * of the elements in the specified collection. That collection's
++     * elements will also be added to the buffer.
++     *
++     * @param coll the collection whose elements to add, may not be null
++     * @throws NullPointerException if the collection is null
++     */
++    public BoundedFifoBuffer(Collection<E> coll) {
++        this(coll.size());
++        addAll(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the buffer out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeInt(size());
++        for (Iterator it = iterator(); it.hasNext();) {
++            out.writeObject(it.next());
++        }
++    }
++
++    /**
++     * Read the buffer in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        elements = (E[]) new Object[maxElements];
++        int size = in.readInt();
++        for (int i = 0; i < size; i++) {
++            elements[i] = (E) in.readObject();
++        }
++        start = 0;
++        full = (size == maxElements);
++        if (full) {
++            end = 0;
++        } else {
++            end = size;
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns the number of elements stored in the buffer.
++     *
++     * @return this buffer's size
++     */
++    public int size() {
++        int size = 0;
++
++        if (end < start) {
++            size = maxElements - start + end;
++        } else if (end == start) {
++            size = (full ? maxElements : 0);
++        } else {
++            size = end - start;
++        }
++
++        return size;
++    }
++
++    /**
++     * Returns true if this buffer is empty; false otherwise.
++     *
++     * @return true if this buffer is empty
++     */
++    public boolean isEmpty() {
++        return size() == 0;
++    }
++
++    /**
++     * Returns true if this collection is full and no new elements can be added.
++     *
++     * @return <code>true</code> if the collection is full
++     */
++    public boolean isFull() {
++        return size() == maxElements;
++    }
++
++    /**
++     * Gets the maximum size of the collection (the bound).
++     *
++     * @return the maximum number of elements the collection can hold
++     */
++    public int maxSize() {
++        return maxElements;
++    }
++
++    /**
++     * Clears this buffer.
++     */
++    public void clear() {
++        full = false;
++        start = 0;
++        end = 0;
++        Arrays.fill(elements, null);
++    }
++
++    /**
++     * Adds the given element to this buffer.
++     *
++     * @param element the element to add
++     * @return true, always
++     * @throws NullPointerException    if the given element is null
++     * @throws BufferOverflowException if this buffer is full
++     */
++    public boolean add(E element) {
++        if (null == element) {
++            throw new NullPointerException("Attempted to add null object to buffer");
++        }
++
++        if (full) {
++            throw new BufferOverflowException("The buffer cannot hold more than " + maxElements + " objects.");
++        }
++
++        elements[end++] = element;
++
++        if (end >= maxElements) {
++            end = 0;
++        }
++
++        if (end == start) {
++            full = true;
++        }
++
++        return true;
++    }
++
++    /**
++     * Returns the least recently inserted element in this buffer.
++     *
++     * @return the least recently inserted element
++     * @throws BufferUnderflowException if the buffer is empty
++     */
++    public E get() {
++        if (isEmpty()) {
++            throw new BufferUnderflowException("The buffer is already empty");
++        }
++
++        return elements[start];
++    }
++
++    /**
++     * Removes the least recently inserted element from this buffer.
++     *
++     * @return the least recently inserted element
++     * @throws BufferUnderflowException if the buffer is empty
++     */
++    public E remove() {
++        if (isEmpty()) {
++            throw new BufferUnderflowException("The buffer is already empty");
++        }
++
++        E element = elements[start];
++
++        if (null != element) {
++            elements[start++] = null;
++
++            if (start >= maxElements) {
++                start = 0;
++            }
++
++            full = false;
++        }
++
++        return element;
++    }
++
++    /**
++     * Increments the internal index.
++     *
++     * @param index the index to increment
++     * @return the updated index
++     */
++    private int increment(int index) {
++        index++;
++        if (index >= maxElements) {
++            index = 0;
++        }
++        return index;
++    }
++
++    /**
++     * Decrements the internal index.
++     *
++     * @param index the index to decrement
++     * @return the updated index
++     */
++    private int decrement(int index) {
++        index--;
++        if (index < 0) {
++            index = maxElements - 1;
++        }
++        return index;
++    }
++
++    /**
++     * Returns an iterator over this buffer's elements.
++     *
++     * @return an iterator over this buffer's elements
++     */
++    public Iterator<E> iterator() {
++        return new Iterator() {
++
++            private int index = start;
++            private int lastReturnedIndex = -1;
++            private boolean isFirst = full;
++
++            public boolean hasNext() {
++                return isFirst || (index != end);
++
++            }
++
++            public E next() {
++                if (!hasNext()) {
++                    throw new NoSuchElementException();
++                }
++                isFirst = false;
++                lastReturnedIndex = index;
++                index = increment(index);
++                return elements[lastReturnedIndex];
++            }
++
++            public void remove() {
++                if (lastReturnedIndex == -1) {
++                    throw new IllegalStateException();
++                }
++
++                // First element can be removed quickly
++                if (lastReturnedIndex == start) {
++                    BoundedFifoBuffer.this.remove();
++                    lastReturnedIndex = -1;
++                    return;
++                }
++
++                // Other elements require us to shift the subsequent elements
++                int i = lastReturnedIndex + 1;
++                while (i != end) {
++                    if (i >= maxElements) {
++                        elements[i - 1] = elements[0];
++                        i = 0;
++                    } else {
++                        elements[i - 1] = elements[i];
++                        i++;
++                    }
++                }
++
++                lastReturnedIndex = -1;
++                end = decrement(end);
++                elements[end] = null;
++                full = false;
++                index = decrement(index);
++            }
++
++        };
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/CircularFifoBuffer.java
+@@ -0,0 +1,97 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.buffer;
++
++import java.util.Collection;
++
++/**
++ * CircularFifoBuffer is a first in first out buffer with a fixed size that
++ * replaces its oldest element if full.
++ * <p/>
++ * The removal order of a <code>CircularFifoBuffer</code> is based on the
++ * insertion order; elements are removed in the same order in which they
++ * were added.  The iteration order is the same as the removal order.
++ * <p/>
++ * The {@link #add(Object)}, {@link #remove()} and {@link #get()} operations
++ * all perform in constant time.  All other operations perform in linear
++ * time or worse.
++ * <p/>
++ * Note that this implementation is not synchronized.  The following can be
++ * used to provide synchronized access to your <code>CircularFifoBuffer</code>:
++ * <pre>
++ *   Buffer fifo = BufferUtils.synchronizedBuffer(new CircularFifoBuffer());
++ * </pre>
++ * <p/>
++ * This buffer prevents null objects from being added.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stefano Fornari
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public class CircularFifoBuffer <E> extends BoundedFifoBuffer<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -8423413834657610406L;
++
++    /**
++     * Constructor that creates a buffer with the default size of 32.
++     */
++    public CircularFifoBuffer() {
++        super(32);
++    }
++
++    /**
++     * Constructor that creates a buffer with the specified size.
++     *
++     * @param size the size of the buffer (cannot be changed)
++     * @throws IllegalArgumentException if the size is less than 1
++     */
++    public CircularFifoBuffer(int size) {
++        super(size);
++    }
++
++    /**
++     * Constructor that creates a buffer from the specified collection.
++     * The collection size also sets the buffer size
++     *
++     * @param coll the collection to copy into the buffer, may not be null
++     * @throws NullPointerException if the collection is null
++     */
++    public CircularFifoBuffer(Collection<E> coll) {
++        super(coll);
++    }
++
++    /**
++     * If the buffer is full, the least recently added element is discarded so
++     * that a new element can be inserted.
++     *
++     * @param element the element to add
++     * @return true, always
++     */
++    public boolean add(E element) {
++        if (isFull()) {
++            remove();
++        }
++        return super.add(element);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/PredicatedBuffer.java
+@@ -0,0 +1,98 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.buffer;
++
++import org.apache.commons.collections15.Buffer;
++import org.apache.commons.collections15.Predicate;
++import org.apache.commons.collections15.collection.PredicatedCollection;
++
++/**
++ * Decorates another <code>Buffer</code> to validate that additions
++ * match a specified predicate.
++ * <p/>
++ * This buffer exists to provide validation for the decorated buffer.
++ * It is normally created to decorate an empty buffer.
++ * If an object cannot be added to the buffer, an IllegalArgumentException is thrown.
++ * <p/>
++ * One usage would be to ensure that no null entries are added to the buffer.
++ * <pre>Buffer buffer = PredicatedBuffer.decorate(new UnboundedFifoBuffer(), NotNullPredicate.INSTANCE);</pre>
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public class PredicatedBuffer <E> extends PredicatedCollection<E> implements Buffer<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 2307609000539943581L;
++
++    /**
++     * Factory method to create a predicated (validating) buffer.
++     * <p/>
++     * If there are any elements already in the buffer being decorated, they
++     * are validated.
++     *
++     * @param buffer    the buffer to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @return a new predicated Buffer
++     * @throws IllegalArgumentException if buffer or predicate is null
++     * @throws IllegalArgumentException if the buffer contains invalid elements
++     */
++    public static <E> Buffer<E> decorate(Buffer<E> buffer, Predicate<? super E> predicate) {
++        return new PredicatedBuffer(buffer, predicate);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the collection being decorated, they
++     * are validated.
++     *
++     * @param buffer    the buffer to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @throws IllegalArgumentException if buffer or predicate is null
++     * @throws IllegalArgumentException if the buffer contains invalid elements
++     */
++    protected PredicatedBuffer(Buffer<E> buffer, Predicate<? super E> predicate) {
++        super(buffer, predicate);
++    }
++
++    /**
++     * Gets the buffer being decorated.
++     *
++     * @return the decorated buffer
++     */
++    protected Buffer<E> getBuffer() {
++        return (Buffer<E>) getCollection();
++    }
++
++    //-----------------------------------------------------------------------
++    public E get() {
++        return getBuffer().get();
++    }
++
++    public E remove() {
++        return getBuffer().remove();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/PriorityBuffer.java
+@@ -0,0 +1,536 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.buffer;
++
++import org.apache.commons.collections15.Buffer;
++import org.apache.commons.collections15.BufferUnderflowException;
++
++import java.util.AbstractCollection;
++import java.util.Comparator;
++import java.util.Iterator;
++import java.util.NoSuchElementException;
++
++/**
++ * Binary heap implementation of <code>Buffer</code> that provides for
++ * removal based on <code>Comparator</code> ordering.
++ * <p/>
++ * The removal order of a binary heap is based on either the natural sort
++ * order of its elements or a specified {@link Comparator}.  The
++ * {@link #remove()} method always returns the first element as determined
++ * by the sort order.  (The <code>ascendingOrder</code> flag in the constructors
++ * can be used to reverse the sort order, in which case {@link #remove()}
++ * will always remove the last element.)  The removal order is
++ * <i>not</i> the same as the order of iteration; elements are
++ * returned by the iterator in no particular order.
++ * <p/>
++ * The {@link #add(Object)} and {@link #remove()} operations perform
++ * in logarithmic time.  The {@link #get()} operation performs in constant
++ * time.  All other operations perform in linear time or worse.
++ * <p/>
++ * Note that this implementation is not synchronized.  Use
++ * {@link org.apache.commons.collections15.BufferUtils#synchronizedBuffer(Buffer)} or
++ * {@link org.apache.commons.collections15.buffer.SynchronizedBuffer#decorate(Buffer)}
++ * to provide synchronized access to a <code>PriorityBuffer</code>:
++ * <p/>
++ * <pre>
++ * Buffer heap = SynchronizedBuffer.decorate(new PriorityBuffer());
++ * </pre>
++ *
++ * @author Peter Donald
++ * @author Ram Chidambaram
++ * @author Michael A. Smith
++ * @author Paul Jack
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0 (previously BinaryHeap v1.0)
++ */
++public class PriorityBuffer <E> extends AbstractCollection<E> implements Buffer<E> {
++
++    /**
++     * The default capacity for the buffer.
++     */
++    private static final int DEFAULT_CAPACITY = 13;
++
++    /**
++     * The elements in this buffer.
++     */
++    protected E[] elements;
++    /**
++     * The number of elements currently in this buffer.
++     */
++    protected int size;
++    /**
++     * If true, the first element as determined by the sort order will
++     * be returned.  If false, the last element as determined by the
++     * sort order will be returned.
++     */
++    protected boolean ascendingOrder;
++    /**
++     * The comparator used to order the elements
++     */
++    protected Comparator<? super E> comparator;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructs a new empty buffer that sorts in ascending order by the
++     * natural order of the objects added.
++     */
++    public PriorityBuffer() {
++        this(DEFAULT_CAPACITY, true, null);
++    }
++
++    /**
++     * Constructs a new empty buffer that sorts in ascending order using the
++     * specified comparator.
++     *
++     * @param comparator the comparator used to order the elements,
++     *                   null means use natural order
++     */
++    public PriorityBuffer(Comparator<? super E> comparator) {
++        this(DEFAULT_CAPACITY, true, comparator);
++    }
++
++    /**
++     * Constructs a new empty buffer specifying the sort order and using the
++     * natural order of the objects added.
++     *
++     * @param ascendingOrder if <code>true</code> the heap is created as a
++     *                       minimum heap; otherwise, the heap is created as a maximum heap
++     */
++    public PriorityBuffer(boolean ascendingOrder) {
++        this(DEFAULT_CAPACITY, ascendingOrder, null);
++    }
++
++    /**
++     * Constructs a new empty buffer specifying the sort order and comparator.
++     *
++     * @param ascendingOrder true to use the order imposed by the given
++     *                       comparator; false to reverse that order
++     * @param comparator     the comparator used to order the elements,
++     *                       null means use natural order
++     */
++    public PriorityBuffer(boolean ascendingOrder, Comparator<? super E> comparator) {
++        this(DEFAULT_CAPACITY, ascendingOrder, comparator);
++    }
++
++    /**
++     * Constructs a new empty buffer that sorts in ascending order by the
++     * natural order of the objects added, specifying an initial capacity.
++     *
++     * @param capacity the initial capacity for the buffer, greater than zero
++     * @throws IllegalArgumentException if <code>capacity</code> is <= <code>0</code>
++     */
++    public PriorityBuffer(int capacity) {
++        this(capacity, true, null);
++    }
++
++    /**
++     * Constructs a new empty buffer that sorts in ascending order using the
++     * specified comparator and initial capacity.
++     *
++     * @param capacity   the initial capacity for the buffer, greater than zero
++     * @param comparator the comparator used to order the elements,
++     *                   null means use natural order
++     * @throws IllegalArgumentException if <code>capacity</code> is <= <code>0</code>
++     */
++    public PriorityBuffer(int capacity, Comparator<? super E> comparator) {
++        this(capacity, true, comparator);
++    }
++
++    /**
++     * Constructs a new empty buffer that specifying initial capacity and
++     * sort order, using the natural order of the objects added.
++     *
++     * @param capacity       the initial capacity for the buffer, greater than zero
++     * @param ascendingOrder if <code>true</code> the heap is created as a
++     *                       minimum heap; otherwise, the heap is created as a maximum heap.
++     * @throws IllegalArgumentException if <code>capacity</code> is <code><= 0</code>
++     */
++    public PriorityBuffer(int capacity, boolean ascendingOrder) {
++        this(capacity, ascendingOrder, null);
++    }
++
++    /**
++     * Constructs a new empty buffer that specifying initial capacity,
++     * sort order and comparator.
++     *
++     * @param capacity       the initial capacity for the buffer, greater than zero
++     * @param ascendingOrder true to use the order imposed by the given
++     *                       comparator; false to reverse that order
++     * @param comparator     the comparator used to order the elements,
++     *                       null means use natural order
++     * @throws IllegalArgumentException if <code>capacity</code> is <code><= 0</code>
++     */
++    public PriorityBuffer(int capacity, boolean ascendingOrder, Comparator<? super E> comparator) {
++        super();
++        if (capacity <= 0) {
++            throw new IllegalArgumentException("invalid capacity");
++        }
++        this.ascendingOrder = ascendingOrder;
++
++        //+1 as 0 is noop
++        this.elements = (E[]) new Object[capacity + 1];
++        this.comparator = comparator;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Checks whether the heap is ascending or descending order.
++     *
++     * @return true if ascending order (a min heap)
++     */
++    public boolean isAscendingOrder() {
++        return ascendingOrder;
++    }
++
++    /**
++     * Gets the comparator being used for this buffer, null is natural order.
++     *
++     * @return the comparator in use, null is natural order
++     */
++    public Comparator<? super E> comparator() {
++        return comparator;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Returns the number of elements in this buffer.
++     *
++     * @return the number of elements in this buffer
++     */
++    public int size() {
++        return size;
++    }
++
++    /**
++     * Clears all elements from the buffer.
++     */
++    public void clear() {
++        elements = (E[]) new Object[elements.length]; // for gc
++        size = 0;
++    }
++
++    /**
++     * Adds an element to the buffer.
++     * <p/>
++     * The element added will be sorted according to the comparator in use.
++     *
++     * @param element the element to be added
++     * @return true always
++     */
++    public boolean add(E element) {
++        if (isAtCapacity()) {
++            grow();
++        }
++        // percolate element to it's place in tree
++        if (ascendingOrder) {
++            percolateUpMinHeap(element);
++        } else {
++            percolateUpMaxHeap(element);
++        }
++        return true;
++    }
++
++    /**
++     * Gets the next element to be removed without actually removing it (peek).
++     *
++     * @return the next element
++     * @throws BufferUnderflowException if the buffer is empty
++     */
++    public E get() {
++        if (isEmpty()) {
++            throw new BufferUnderflowException();
++        } else {
++            return elements[1];
++        }
++    }
++
++    /**
++     * Gets and removes the next element (pop).
++     *
++     * @return the next element
++     * @throws BufferUnderflowException if the buffer is empty
++     */
++    public E remove() {
++        final E result = get();
++        elements[1] = elements[size--];
++
++        // set the unused element to 'null' so that the garbage collector
++        // can free the object if not used anywhere else.(remove reference)
++        elements[size + 1] = null;
++
++        if (size != 0) {
++            // percolate top element to it's place in tree
++            if (ascendingOrder) {
++                percolateDownMinHeap(1);
++            } else {
++                percolateDownMaxHeap(1);
++            }
++        }
++
++        return result;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Tests if the buffer is at capacity.
++     *
++     * @return <code>true</code> if buffer is full; <code>false</code> otherwise.
++     */
++    protected boolean isAtCapacity() {
++        //+1 as element 0 is noop
++        return elements.length == size + 1;
++    }
++
++
++    /**
++     * Percolates element down heap from the position given by the index.
++     * <p/>
++     * Assumes it is a minimum heap.
++     *
++     * @param index the index for the element
++     */
++    protected void percolateDownMinHeap(final int index) {
++        final E element = elements[index];
++        int hole = index;
++
++        while ((hole * 2) <= size) {
++            int child = hole * 2;
++
++            // if we have a right child and that child can not be percolated
++            // up then move onto other child
++            if (child != size && compare(elements[child + 1], elements[child]) < 0) {
++                child++;
++            }
++
++            // if we found resting place of bubble then terminate search
++            if (compare(elements[child], element) >= 0) {
++                break;
++            }
++
++            elements[hole] = elements[child];
++            hole = child;
++        }
++
++        elements[hole] = element;
++    }
++
++    /**
++     * Percolates element down heap from the position given by the index.
++     * <p/>
++     * Assumes it is a maximum heap.
++     *
++     * @param index the index of the element
++     */
++    protected void percolateDownMaxHeap(final int index) {
++        final E element = elements[index];
++        int hole = index;
++
++        while ((hole * 2) <= size) {
++            int child = hole * 2;
++
++            // if we have a right child and that child can not be percolated
++            // up then move onto other child
++            if (child != size && compare(elements[child + 1], elements[child]) > 0) {
++                child++;
++            }
++
++            // if we found resting place of bubble then terminate search
++            if (compare(elements[child], element) <= 0) {
++                break;
++            }
++
++            elements[hole] = elements[child];
++            hole = child;
++        }
++
++        elements[hole] = element;
++    }
++
++    /**
++     * Percolates element up heap from the position given by the index.
++     * <p/>
++     * Assumes it is a minimum heap.
++     *
++     * @param index the index of the element to be percolated up
++     */
++    protected void percolateUpMinHeap(final int index) {
++        int hole = index;
++        E element = elements[hole];
++        while (hole > 1 && compare(element, elements[hole / 2]) < 0) {
++            // save element that is being pushed down
++            // as the element "bubble" is percolated up
++            final int next = hole / 2;
++            elements[hole] = elements[next];
++            hole = next;
++        }
++        elements[hole] = element;
++    }
++
++    /**
++     * Percolates a new element up heap from the bottom.
++     * <p/>
++     * Assumes it is a minimum heap.
++     *
++     * @param element the element
++     */
++    protected void percolateUpMinHeap(final E element) {
++        elements[++size] = element;
++        percolateUpMinHeap(size);
++    }
++
++    /**
++     * Percolates element up heap from from the position given by the index.
++     * <p/>
++     * Assume it is a maximum heap.
++     *
++     * @param index the index of the element to be percolated up
++     */
++    protected void percolateUpMaxHeap(final int index) {
++        int hole = index;
++        E element = elements[hole];
++
++        while (hole > 1 && compare(element, elements[hole / 2]) > 0) {
++            // save element that is being pushed down
++            // as the element "bubble" is percolated up
++            final int next = hole / 2;
++            elements[hole] = elements[next];
++            hole = next;
++        }
++
++        elements[hole] = element;
++    }
++
++    /**
++     * Percolates a new element up heap from the bottom.
++     * <p/>
++     * Assume it is a maximum heap.
++     *
++     * @param element the element
++     */
++    protected void percolateUpMaxHeap(final E element) {
++        elements[++size] = element;
++        percolateUpMaxHeap(size);
++    }
++
++    /**
++     * Compares two objects using the comparator if specified, or the
++     * natural order otherwise.
++     *
++     * @param a the first object
++     * @param b the second object
++     * @return -ve if a less than b, 0 if they are equal, +ve if a greater than b
++     */
++    protected int compare(E a, E b) {
++        if (comparator != null) {
++            return comparator.compare(a, b);
++        } else {
++            return ((Comparable) a).compareTo(b);
++        }
++    }
++
++    /**
++     * Increases the size of the heap to support additional elements
++     */
++    protected void grow() {
++        final E[] array = (E[]) new Object[elements.length * 2];
++        System.arraycopy(elements, 0, array, 0, elements.length);
++        elements = array;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns an iterator over this heap's elements.
++     *
++     * @return an iterator over this heap's elements
++     */
++    public Iterator<E> iterator() {
++        return new Iterator<E>() {
++
++            private int index = 1;
++            private int lastReturnedIndex = -1;
++
++            public boolean hasNext() {
++                return index <= size;
++            }
++
++            public E next() {
++                if (!hasNext()) {
++                    throw new NoSuchElementException();
++                }
++                lastReturnedIndex = index;
++                index++;
++                return elements[lastReturnedIndex];
++            }
++
++            public void remove() {
++                if (lastReturnedIndex == -1) {
++                    throw new IllegalStateException();
++                }
++                elements[lastReturnedIndex] = elements[size];
++                elements[size] = null;
++                size--;
++                if (size != 0 && lastReturnedIndex <= size) {
++                    int compareToParent = 0;
++                    if (lastReturnedIndex > 1) {
++                        compareToParent = compare(elements[lastReturnedIndex], elements[lastReturnedIndex / 2]);
++                    }
++                    if (ascendingOrder) {
++                        if (lastReturnedIndex > 1 && compareToParent < 0) {
++                            percolateUpMinHeap(lastReturnedIndex);
++                        } else {
++                            percolateDownMinHeap(lastReturnedIndex);
++                        }
++                    } else {  // max heap
++                        if (lastReturnedIndex > 1 && compareToParent > 0) {
++                            percolateUpMaxHeap(lastReturnedIndex);
++                        } else {
++                            percolateDownMaxHeap(lastReturnedIndex);
++                        }
++                    }
++                }
++                index--;
++                lastReturnedIndex = -1;
++            }
++
++        };
++    }
++
++    /**
++     * Returns a string representation of this heap.  The returned string
++     * is similar to those produced by standard JDK collections15.
++     *
++     * @return a string representation of this heap
++     */
++    public String toString() {
++        final StringBuffer sb = new StringBuffer();
++
++        sb.append("[ ");
++
++        for (int i = 1; i < size + 1; i++) {
++            if (i != 1) {
++                sb.append(", ");
++            }
++            sb.append(elements[i]);
++        }
++
++        sb.append(" ]");
++
++        return sb.toString();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/SynchronizedBuffer.java
+@@ -0,0 +1,96 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.buffer;
++
++import org.apache.commons.collections15.Buffer;
++import org.apache.commons.collections15.collection.SynchronizedCollection;
++
++/**
++ * Decorates another <code>Buffer</code> to synchronize its behaviour
++ * for a multi-threaded environment.
++ * <p/>
++ * Methods are synchronized, then forwarded to the decorated buffer.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public class SynchronizedBuffer <E> extends SynchronizedCollection<E> implements Buffer<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -6859936183953626253L;
++
++    /**
++     * Factory method to create a synchronized buffer.
++     *
++     * @param buffer the buffer to decorate, must not be null
++     * @return a new synchronized Buffer
++     * @throws IllegalArgumentException if buffer is null
++     */
++    public static <E> Buffer<E> decorate(Buffer<E> buffer) {
++        return new SynchronizedBuffer(buffer);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param buffer the buffer to decorate, must not be null
++     * @throws IllegalArgumentException if the buffer is null
++     */
++    protected SynchronizedBuffer(Buffer<E> buffer) {
++        super(buffer);
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param buffer the buffer to decorate, must not be null
++     * @param lock   the lock object to use, must not be null
++     * @throws IllegalArgumentException if the buffer is null
++     */
++    protected SynchronizedBuffer(Buffer<E> buffer, Object lock) {
++        super(buffer, lock);
++    }
++
++    /**
++     * Gets the buffer being decorated.
++     *
++     * @return the decorated buffer
++     */
++    protected Buffer<E> getBuffer() {
++        return (Buffer<E>) collection;
++    }
++
++    //-----------------------------------------------------------------------
++    public E get() {
++        synchronized (lock) {
++            return getBuffer().get();
++        }
++    }
++
++    public E remove() {
++        synchronized (lock) {
++            return getBuffer().remove();
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/TransformedBuffer.java
+@@ -0,0 +1,94 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.buffer;
++
++import org.apache.commons.collections15.Buffer;
++import org.apache.commons.collections15.Transformer;
++import org.apache.commons.collections15.collection.TransformedCollection;
++
++/**
++ * Decorates another <code>Buffer</code> to transform objects that are added.
++ * <p/>
++ * The add methods are affected by this class.
++ * Thus objects must be removed or searched for using their transformed form.
++ * For example, if the transformation converts Strings to Integers, you must
++ * use the Integer form to remove objects.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ * <p>
++ * Note: This class cannot support generics without breaking the Collection contract.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public class TransformedBuffer <I,O> extends TransformedCollection<I, O> implements Buffer {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -7901091318986132033L;
++
++    /**
++     * Factory method to create a transforming buffer.
++     * <p/>
++     * If there are any elements already in the buffer being decorated, they
++     * are NOT transformed.
++     *
++     * @param buffer      the buffer to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @return a new transformed Buffer
++     * @throws IllegalArgumentException if buffer or transformer is null
++     */
++    public static <I,O> Buffer<O> decorate(Buffer<I> buffer, Transformer<? super I, ? extends O> transformer) {
++        return new TransformedBuffer<I, O>(buffer, transformer);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the buffer being decorated, they
++     * are NOT transformed.
++     *
++     * @param buffer      the buffer to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @throws IllegalArgumentException if buffer or transformer is null
++     */
++    protected TransformedBuffer(Buffer<I> buffer, Transformer<? super I, ? extends O> transformer) {
++        super(buffer, transformer);
++    }
++
++    /**
++     * Gets the decorated buffer.
++     *
++     * @return the decorated buffer
++     */
++    protected Buffer<O> getBuffer() {
++        return (Buffer<O>) collection;
++    }
++
++    //-----------------------------------------------------------------------
++    public Object get() {
++        return getBuffer().get();
++    }
++
++    public Object remove() {
++        return getBuffer().remove();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/TypedBuffer.java
+@@ -0,0 +1,60 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.buffer;
++
++import org.apache.commons.collections15.Buffer;
++import org.apache.commons.collections15.functors.InstanceofPredicate;
++
++/**
++ * Decorates another <code>Buffer</code> to validate that elements added
++ * are of a specific type.
++ * <p/>
++ * The validation of additions is performed via an instanceof test against
++ * a specified <code>Class</code>. If an object cannot be added to the
++ * collection, an IllegalArgumentException is thrown.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @author Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public class TypedBuffer <E> {
++
++    /**
++     * Factory method to create a typed list.
++     * <p/>
++     * If there are any elements already in the buffer being decorated, they
++     * are validated.
++     *
++     * @param buffer the buffer to decorate, must not be null
++     * @param type   the type to allow into the buffer, must not be null
++     * @return a new typed Buffer
++     * @throws IllegalArgumentException if buffer or type is null
++     * @throws IllegalArgumentException if the buffer contains invalid elements
++     */
++    public static <E> Buffer<E> decorate(Buffer<E> buffer, Class type) {
++        return new PredicatedBuffer<E>(buffer, InstanceofPredicate.getInstance(type));
++    }
++
++    /**
++     * Restrictive constructor.
++     */
++    protected TypedBuffer() {
++        super();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/UnboundedFifoBuffer.java
+@@ -0,0 +1,334 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.buffer;
++
++import org.apache.commons.collections15.Buffer;
++import org.apache.commons.collections15.BufferUnderflowException;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.AbstractCollection;
++import java.util.Iterator;
++import java.util.NoSuchElementException;
++
++/**
++ * UnboundedFifoBuffer is a very efficient buffer implementation.
++ * According to performance testing, it exhibits a constant access time, but it
++ * also outperforms ArrayList when used for the same purpose.
++ * <p/>
++ * The removal order of an <code>UnboundedFifoBuffer</code> is based on the insertion
++ * order; elements are removed in the same order in which they were added.
++ * The iteration order is the same as the removal order.
++ * <p/>
++ * The {@link #remove()} and {@link #get()} operations perform in constant time.
++ * The {@link #add(Object)} operation performs in amortized constant time.  All
++ * other operations perform in linear time or worse.
++ * <p/>
++ * Note that this implementation is not synchronized.  The following can be
++ * used to provide synchronized access to your <code>UnboundedFifoBuffer</code>:
++ * <pre>
++ *   Buffer fifo = BufferUtils.synchronizedBuffer(new UnboundedFifoBuffer());
++ * </pre>
++ * <p/>
++ * This buffer prevents null objects from being added.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Avalon
++ * @author Federico Barbieri
++ * @author Berin Loritsch
++ * @author Paul Jack
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0 (previously in main package v2.1)
++ */
++public class UnboundedFifoBuffer <E> extends AbstractCollection<E> implements Buffer<E>, Serializable {
++
++    /**
++     * Serialization vesrion
++     */
++    private static final long serialVersionUID = -3482960336579541419L;
++
++    /**
++     * The array of objects in the buffer.
++     */
++    protected transient E[] buffer;
++    /**
++     * The current head index.
++     */
++    protected transient int head;
++    /**
++     * The current tail index.
++     */
++    protected transient int tail;
++
++    /**
++     * Constructs an UnboundedFifoBuffer with the default number of elements.
++     * It is exactly the same as performing the following:
++     * <p/>
++     * <pre>
++     *   new UnboundedFifoBuffer(32);
++     * </pre>
++     */
++    public UnboundedFifoBuffer() {
++        this(32);
++    }
++
++    /**
++     * Constructs an UnboundedFifoBuffer with the specified number of elements.
++     * The integer must be a positive integer.
++     *
++     * @param initialSize the initial size of the buffer
++     * @throws IllegalArgumentException if the size is less than 1
++     */
++    public UnboundedFifoBuffer(int initialSize) {
++        if (initialSize <= 0) {
++            throw new IllegalArgumentException("The size must be greater than 0");
++        }
++        buffer = (E[]) new Object[initialSize + 1];
++        head = 0;
++        tail = 0;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the buffer out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeInt(size());
++        for (Iterator it = iterator(); it.hasNext();) {
++            out.writeObject(it.next());
++        }
++    }
++
++    /**
++     * Read the buffer in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        int size = in.readInt();
++        buffer = (E[]) new Object[size];
++        for (int i = 0; i < size; i++) {
++            buffer[i] = (E) in.readObject();
++        }
++        head = 0;
++        tail = size;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns the number of elements stored in the buffer.
++     *
++     * @return this buffer's size
++     */
++    public int size() {
++        int size = 0;
++
++        if (tail < head) {
++            size = buffer.length - head + tail;
++        } else {
++            size = tail - head;
++        }
++
++        return size;
++    }
++
++    /**
++     * Returns true if this buffer is empty; false otherwise.
++     *
++     * @return true if this buffer is empty
++     */
++    public boolean isEmpty() {
++        return (size() == 0);
++    }
++
++    /**
++     * Adds the given element to this buffer.
++     *
++     * @param obj the element to add
++     * @return true, always
++     * @throws NullPointerException if the given element is null
++     */
++    public boolean add(final E obj) {
++        if (obj == null) {
++            throw new NullPointerException("Attempted to add null object to buffer");
++        }
++
++        if (size() + 1 >= buffer.length) {
++            E[] tmp = (E[]) new Object[((buffer.length - 1) * 2) + 1];
++
++            int j = 0;
++            for (int i = head; i != tail;) {
++                tmp[j] = buffer[i];
++                buffer[i] = null;
++
++                j++;
++                i++;
++                if (i == buffer.length) {
++                    i = 0;
++                }
++            }
++
++            buffer = tmp;
++            head = 0;
++            tail = j;
++        }
++
++        buffer[tail] = obj;
++        tail++;
++        if (tail >= buffer.length) {
++            tail = 0;
++        }
++        return true;
++    }
++
++    /**
++     * Returns the next object in the buffer.
++     *
++     * @return the next object in the buffer
++     * @throws BufferUnderflowException if this buffer is empty
++     */
++    public E get() {
++        if (isEmpty()) {
++            throw new BufferUnderflowException("The buffer is already empty");
++        }
++
++        return buffer[head];
++    }
++
++    /**
++     * Removes the next object from the buffer
++     *
++     * @return the removed object
++     * @throws BufferUnderflowException if this buffer is empty
++     */
++    public E remove() {
++        if (isEmpty()) {
++            throw new BufferUnderflowException("The buffer is already empty");
++        }
++
++        E element = buffer[head];
++
++        if (null != element) {
++            buffer[head] = null;
++
++            head++;
++            if (head >= buffer.length) {
++                head = 0;
++            }
++        }
++
++        return element;
++    }
++
++    /**
++     * Increments the internal index.
++     *
++     * @param index the index to increment
++     * @return the updated index
++     */
++    private int increment(int index) {
++        index++;
++        if (index >= buffer.length) {
++            index = 0;
++        }
++        return index;
++    }
++
++    /**
++     * Decrements the internal index.
++     *
++     * @param index the index to decrement
++     * @return the updated index
++     */
++    private int decrement(int index) {
++        index--;
++        if (index < 0) {
++            index = buffer.length - 1;
++        }
++        return index;
++    }
++
++    /**
++     * Returns an iterator over this buffer's elements.
++     *
++     * @return an iterator over this buffer's elements
++     */
++    public Iterator<E> iterator() {
++        return new Iterator<E>() {
++
++            private int index = head;
++            private int lastReturnedIndex = -1;
++
++            public boolean hasNext() {
++                return index != tail;
++
++            }
++
++            public E next() {
++                if (!hasNext()) {
++                    throw new NoSuchElementException();
++                }
++                lastReturnedIndex = index;
++                index = increment(index);
++                return buffer[lastReturnedIndex];
++            }
++
++            public void remove() {
++                if (lastReturnedIndex == -1) {
++                    throw new IllegalStateException();
++                }
++
++                // First element can be removed quickly
++                if (lastReturnedIndex == head) {
++                    UnboundedFifoBuffer.this.remove();
++                    lastReturnedIndex = -1;
++                    return;
++                }
++
++                // Other elements require us to shift the subsequent elements
++                int i = lastReturnedIndex + 1;
++                while (i != tail) {
++                    if (i >= buffer.length) {
++                        buffer[i - 1] = buffer[0];
++                        i = 0;
++                    } else {
++                        buffer[i - 1] = buffer[i];
++                        i++;
++                    }
++                }
++
++                lastReturnedIndex = -1;
++                tail = decrement(tail);
++                buffer[tail] = null;
++                index = decrement(index);
++            }
++
++        };
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/UnmodifiableBuffer.java
+@@ -0,0 +1,131 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.buffer;
++
++import org.apache.commons.collections15.Buffer;
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.iterators.UnmodifiableIterator;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Iterator;
++
++/**
++ * Decorates another <code>Buffer</code> to ensure it can't be altered.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableBuffer <E> extends AbstractBufferDecorator<E> implements Unmodifiable, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 1832948656215393357L;
++
++    /**
++     * Factory method to create an unmodifiable buffer.
++     * <p/>
++     * If the buffer passed in is already unmodifiable, it is returned.
++     *
++     * @param buffer the buffer to decorate, must not be null
++     * @return an unmodifiable Buffer
++     * @throws IllegalArgumentException if buffer is null
++     */
++    public static <E> Buffer<E> decorate(Buffer<E> buffer) {
++        if (buffer instanceof Unmodifiable) {
++            return buffer;
++        }
++        return new UnmodifiableBuffer<E>(buffer);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param buffer the buffer to decorate, must not be null
++     * @throws IllegalArgumentException if buffer is null
++     */
++    private UnmodifiableBuffer(Buffer<E> buffer) {
++        super(buffer);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the collection out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(collection);
++    }
++
++    /**
++     * Read the collection in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        collection = (Collection<E>) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    public Iterator<E> iterator() {
++        return UnmodifiableIterator.decorate(getCollection().iterator());
++    }
++
++    public boolean add(E object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean remove(Object object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    //-----------------------------------------------------------------------
++    public E remove() {
++        throw new UnsupportedOperationException();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/buffer/package.html
+@@ -0,0 +1,40 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:20 pents90 Exp $ -->
++ <!--
++   Copyright 2003-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<BODY>
++<p>
++This package contains implementations of the
++{@link org.apache.commons.collections.Buffer Buffer} interface.
++<p>
++The following implementations are provided in the package:
++<ul>
++<li>PriorityBuffer - provides for removal based on a comparator ordering
++<li>BoundedFifoBuffer - implements a buffer with a fixed size that throws exceptions when full
++<li>CircularFifoBuffer - implements a buffer with a fixed size that discards oldest when full
++<li>UnboundedFifoBuffer - implements a buffer that grows in size if necessary
++</ul>
++<p>
++The following decorators are provided in the package:
++<ul>
++<li>Synchronized - synchronizes method access for multi-threaded environments
++<li>Unmodifiable - ensures the collection cannot be altered
++<li>Predicated - ensures that only elements that are valid according to a predicate can be added
++<li>Typed - ensures that only elements that are of a specific type can be added
++<li>Transformed - transforms elements added to the buffer
++<li>Blocking - blocks on get and remove until an element is available
++</ul>
++</pre>
++</BODY>
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/collection/AbstractCollectionDecorator.java
+@@ -0,0 +1,148 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.collection;
++
++import java.util.Collection;
++import java.util.Iterator;
++
++/**
++ * Decorates another <code>Collection</code> to provide additional behaviour.
++ * <p/>
++ * Each method call made on this <code>Collection</code> is forwarded to the
++ * decorated <code>Collection</code>. This class is used as a framework on which
++ * to build to extensions such as synchronized and unmodifiable behaviour. The
++ * main advantage of decoration is that one decorator can wrap any implementation
++ * of <code>Collection</code>, whereas sub-classing requires a new class to be
++ * written for each implementation.
++ * <p/>
++ * This implementation does not perform any special processing with
++ * {@link #iterator()}. Instead it simply returns the value from the
++ * wrapped collection. This may be undesirable, for example if you are trying
++ * to write an unmodifiable implementation it might provide a loophole.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractCollectionDecorator <E> implements Collection<E> {
++
++    /**
++     * The collection being decorated
++     */
++    protected Collection<E> collection;
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     *
++     * @since Commons Collections 3.1
++     */
++    protected AbstractCollectionDecorator() {
++        super();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param coll the collection to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    protected AbstractCollectionDecorator(Collection<E> coll) {
++        if (coll == null) {
++            throw new IllegalArgumentException("Collection must not be null");
++        }
++        this.collection = coll;
++    }
++
++    /**
++     * Gets the collection being decorated.
++     *
++     * @return the decorated collection
++     */
++    protected Collection<E> getCollection() {
++        return collection;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(E object) {
++        return collection.add(object);
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        return collection.addAll(coll);
++    }
++
++    public void clear() {
++        collection.clear();
++    }
++
++    public boolean contains(Object object) {
++        return collection.contains(object);
++    }
++
++    public boolean isEmpty() {
++        return collection.isEmpty();
++    }
++
++    public Iterator<E> iterator() {
++        return collection.iterator();
++    }
++
++    public boolean remove(Object object) {
++        return collection.remove(object);
++    }
++
++    public int size() {
++        return collection.size();
++    }
++
++    public Object[] toArray() {
++        return (Object[]) collection.toArray();
++    }
++
++    public <T> T[] toArray(T[] object) {
++        return (T[]) collection.toArray(object);
++    }
++
++    public boolean containsAll(Collection<?> coll) {
++        return collection.containsAll(coll);
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        return collection.removeAll(coll);
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        return collection.retainAll(coll);
++    }
++
++    public boolean equals(Object object) {
++        if (object == this) {
++            return true;
++        }
++        return collection.equals(object);
++    }
++
++    public int hashCode() {
++        return collection.hashCode();
++    }
++
++    public String toString() {
++        return collection.toString();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/collection/AbstractSerializableCollectionDecorator.java
+@@ -0,0 +1,69 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.collection;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++
++/**
++ * Serializable subclass of AbstractCollectionDecorator.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @since Commons Collections 3.1
++ */
++public abstract class AbstractSerializableCollectionDecorator <E> extends AbstractCollectionDecorator<E> implements Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 6249888059822088500L;
++
++    /**
++     * Constructor.
++     */
++    protected AbstractSerializableCollectionDecorator(Collection<E> coll) {
++        super(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the collection out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(collection);
++    }
++
++    /**
++     * Read the collection in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        collection = (Collection<E>) in.readObject();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/collection/CompositeCollection.java
+@@ -0,0 +1,444 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.collection;
++
++import org.apache.commons.collections15.iterators.EmptyIterator;
++import org.apache.commons.collections15.iterators.IteratorChain;
++import org.apache.commons.collections15.list.UnmodifiableList;
++
++import java.lang.reflect.Array;
++import java.util.ArrayList;
++import java.util.Arrays;
++import java.util.Collection;
++import java.util.Iterator;
++
++/**
++ * Decorates a collection of other collections15 to provide a single unified view.
++ * <p/>
++ * Changes made to this collection will actually be made on the decorated collection.
++ * Add and remove operations require the use of a pluggable strategy. If no
++ * strategy is provided then add and remove are unsupported.
++ *
++ * @author Brian McCallister
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Phil Steitz
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public class CompositeCollection <E> implements Collection<E> {
++
++    /**
++     * CollectionMutator to handle changes to the collection
++     */
++    protected CollectionMutator<E> mutator;
++
++    /**
++     * Collections in the composite
++     */
++    protected Collection<E>[] all;
++
++    /**
++     * Create an empty CompositeCollection.
++     */
++    public CompositeCollection() {
++        super();
++        this.all = new Collection[0];
++    }
++
++    /**
++     * Create a Composite Collection with only coll composited.
++     *
++     * @param coll a collection to decorate
++     */
++    public CompositeCollection(Collection<E> coll) {
++        this();
++        this.addComposited(coll);
++    }
++
++    /**
++     * Create a CompositeCollection with colls as the initial list of
++     * composited collections15.
++     *
++     * @param colls a variable number of collections15 to decorate
++     */
++    public CompositeCollection(Collection<E>... colls) {
++        this();
++        this.addComposited(colls);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the size of this composite collection.
++     * <p/>
++     * This implementation calls <code>size()</code> on each collection.
++     *
++     * @return total number of elements in all contained containers
++     */
++    public int size() {
++        int size = 0;
++        for (int i = this.all.length - 1; i >= 0; i--) {
++            size += this.all[i].size();
++        }
++        return size;
++    }
++
++    /**
++     * Checks whether this composite collection is empty.
++     * <p/>
++     * This implementation calls <code>isEmpty()</code> on each collection.
++     *
++     * @return true if all of the contained collections15 are empty
++     */
++    public boolean isEmpty() {
++        for (int i = this.all.length - 1; i >= 0; i--) {
++            if (this.all[i].isEmpty() == false) {
++                return false;
++            }
++        }
++        return true;
++    }
++
++    /**
++     * Checks whether this composite collection contains the object.
++     * <p/>
++     * This implementation calls <code>contains()</code> on each collection.
++     *
++     * @param obj the object to search for
++     * @return true if obj is contained in any of the contained collections15
++     */
++    public boolean contains(Object obj) {
++        for (int i = this.all.length - 1; i >= 0; i--) {
++            if (this.all[i].contains(obj)) {
++                return true;
++            }
++        }
++        return false;
++    }
++
++    /**
++     * Gets an iterator over all the collections15 in this composite.
++     * <p/>
++     * This implementation uses an <code>IteratorChain</code>.
++     *
++     * @return an <code>IteratorChain</code> instance which supports
++     *         <code>remove()</code>. Iteration occurs over contained collections15 in
++     *         the order they were added, but this behavior should not be relied upon.
++     * @see IteratorChain
++     */
++    public Iterator<E> iterator() {
++        if (this.all.length == 0) {
++            return EmptyIterator.INSTANCE;
++        }
++        IteratorChain<E> chain = new IteratorChain<E>();
++        for (int i = 0; i < this.all.length; ++i) {
++            chain.addIterator(this.all[i].iterator());
++        }
++        return chain;
++    }
++
++    /**
++     * Returns an array containing all of the elements in this composite.
++     *
++     * @return an object array of all the elements in the collection
++     */
++    public E[] toArray() {
++        final E[] result = (E[]) new Object[this.size()];
++        int i = 0;
++        for (Iterator<E> it = this.iterator(); it.hasNext(); i++) {
++            result[i] = (E) it.next();
++        }
++        return result;
++    }
++
++    /**
++     * Returns an object array, populating the supplied array if possible.
++     * See <code>Collection</code> interface for full details.
++     *
++     * @param array the array to use, populating if possible
++     * @return an array of all the elements in the collection
++     */
++
++    public <E> E[] toArray(E[] array) {
++        int size = this.size();
++        E[] result = null;
++        if (array.length >= size) {
++            result = array;
++        } else {
++            result = (E[]) Array.newInstance(array.getClass().getComponentType(), size);
++        }
++
++        int offset = 0;
++        for (int i = 0; i < this.all.length; ++i) {
++            for (Iterator it = this.all[i].iterator(); it.hasNext();) {
++                result[offset++] = (E) it.next();
++            }
++        }
++        if (result.length > size) {
++            result[size] = null;
++        }
++        return result;
++    }
++
++    /**
++     * Adds an object to the collection, throwing UnsupportedOperationException
++     * unless a CollectionMutator strategy is specified.
++     *
++     * @param obj the object to add
++     * @return true if the collection was modified
++     * @throws UnsupportedOperationException if CollectionMutator hasn't been set
++     * @throws UnsupportedOperationException if add is unsupported
++     * @throws ClassCastException            if the object cannot be added due to its type
++     * @throws NullPointerException          if the object cannot be added because its null
++     * @throws IllegalArgumentException      if the object cannot be added
++     */
++    public boolean add(E obj) {
++        if (this.mutator == null) {
++            throw new UnsupportedOperationException("add() is not supported on CompositeCollection without a CollectionMutator strategy");
++        }
++        return this.mutator.add(this, this.all, obj);
++    }
++
++    /**
++     * Removes an object from the collection, throwing UnsupportedOperationException
++     * unless a CollectionMutator strategy is specified.
++     *
++     * @param obj the object being removed
++     * @return true if the collection is changed
++     * @throws UnsupportedOperationException if removed is unsupported
++     * @throws ClassCastException            if the object cannot be removed due to its type
++     * @throws NullPointerException          if the object cannot be removed because its null
++     * @throws IllegalArgumentException      if the object cannot be removed
++     */
++    public boolean remove(Object obj) {
++        if (this.mutator == null) {
++            throw new UnsupportedOperationException("remove() is not supported on CompositeCollection without a CollectionMutator strategy");
++        }
++        return this.mutator.remove(this, this.all, obj);
++    }
++
++    /**
++     * Checks whether this composite contains all the elements in the specified collection.
++     * <p/>
++     * This implementation calls <code>contains()</code> for each element in the
++     * specified collection.
++     *
++     * @param coll the collection to check for
++     * @return true if all elements contained
++     */
++    public boolean containsAll(Collection<?> coll) {
++        for (Iterator it = coll.iterator(); it.hasNext();) {
++            if (this.contains(it.next()) == false) {
++                return false;
++            }
++        }
++        return true;
++    }
++
++    /**
++     * Adds a collection of elements to this collection, throwing
++     * UnsupportedOperationException unless a CollectionMutator strategy is specified.
++     *
++     * @param coll the collection to add
++     * @return true if the collection was modified
++     * @throws UnsupportedOperationException if CollectionMutator hasn't been set
++     * @throws UnsupportedOperationException if add is unsupported
++     * @throws ClassCastException            if the object cannot be added due to its type
++     * @throws NullPointerException          if the object cannot be added because its null
++     * @throws IllegalArgumentException      if the object cannot be added
++     */
++    public boolean addAll(Collection<? extends E> coll) {
++        if (this.mutator == null) {
++            throw new UnsupportedOperationException("addAll() is not supported on CompositeCollection without a CollectionMutator strategy");
++        }
++        return this.mutator.addAll(this, this.all, coll);
++    }
++
++    /**
++     * Removes the elements in the specified collection from this composite collection.
++     * <p/>
++     * This implementation calls <code>removeAll</code> on each collection.
++     *
++     * @param coll the collection to remove
++     * @return true if the collection was modified
++     * @throws UnsupportedOperationException if removeAll is unsupported
++     */
++    public boolean removeAll(Collection<?> coll) {
++        if (coll.size() == 0) {
++            return false;
++        }
++        boolean changed = false;
++        for (int i = this.all.length - 1; i >= 0; i--) {
++            changed = (this.all[i].removeAll(coll) || changed);
++        }
++        return changed;
++    }
++
++    /**
++     * Retains all the elements in the specified collection in this composite collection,
++     * removing all others.
++     * <p/>
++     * This implementation calls <code>retainAll()</code> on each collection.
++     *
++     * @param coll the collection to remove
++     * @return true if the collection was modified
++     * @throws UnsupportedOperationException if retainAll is unsupported
++     */
++    public boolean retainAll(final Collection<?> coll) {
++        boolean changed = false;
++        for (int i = this.all.length - 1; i >= 0; i--) {
++            changed = (this.all[i].retainAll(coll) || changed);
++        }
++        return changed;
++    }
++
++    /**
++     * Removes all of the elements from this collection .
++     * <p/>
++     * This implementation calls <code>clear()</code> on each collection.
++     *
++     * @throws UnsupportedOperationException if clear is unsupported
++     */
++    public void clear() {
++        for (int i = 0; i < this.all.length; ++i) {
++            this.all[i].clear();
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Specify a CollectionMutator strategy instance to handle changes.
++     *
++     * @param mutator the mutator to use
++     */
++    public void setMutator(CollectionMutator<E> mutator) {
++        this.mutator = mutator;
++    }
++
++    /**
++     * Add these Collections to the list of collections15 in this composite
++     *
++     * @param comps Collections to be appended to the composite
++     */
++    public void addComposited(Collection<? extends E>... comps) {
++        ArrayList list = new ArrayList(Arrays.asList(this.all));
++        list.addAll(Arrays.asList(comps));
++        all = (Collection<E>[]) list.toArray(new Collection[list.size()]);
++    }
++
++    /**
++     * Add an additional collection to this composite.
++     *
++     * @param c the collection to add
++     */
++    public void addComposited(Collection<? extends E> c) {
++        this.addComposited(new Collection[]{c});
++    }
++
++    /**
++     * Add two additional collections15 to this composite.
++     *
++     * @deprecated Superceded by the variable argument implementation of addComposited()
++     * @param c the first collection to add
++     * @param d the second collection to add
++     */
++    public void addComposited(Collection<? extends E> c, Collection<? extends E> d) {
++        this.addComposited(new Collection[]{c, d});
++    }
++
++    /**
++     * Removes a collection from the those being decorated in this composite.
++     *
++     * @param coll collection to be removed
++     */
++    public void removeComposited(Collection<? extends E> coll) {
++        ArrayList list = new ArrayList(this.all.length);
++        list.addAll(Arrays.asList(this.all));
++        list.remove(coll);
++        this.all = (Collection<E>[]) list.toArray(new Collection[list.size()]);
++    }
++
++    /**
++     * Returns a new collection containing all of the elements
++     *
++     * @return A new ArrayList containing all of the elements in this composite.
++     *         The new collection is <i>not</i> backed by this composite.
++     */
++    public Collection<E> toCollection() {
++        return new ArrayList<E>(this);
++    }
++
++    /**
++     * Gets the collections15 being decorated.
++     *
++     * @return Unmodifiable collection of all collections15 in this composite.
++     */
++    public Collection<Collection<E>> getCollections() {
++        return UnmodifiableList.decorate(Arrays.asList(this.all));
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Pluggable strategy to handle changes to the composite.
++     */
++    public interface CollectionMutator <E> {
++
++        /**
++         * Called when an object is to be added to the composite.
++         *
++         * @param composite   the CompositeCollection being changed
++         * @param collections all of the Collection instances in this CompositeCollection
++         * @param obj         the object being added
++         * @return true if the collection is changed
++         * @throws UnsupportedOperationException if add is unsupported
++         * @throws ClassCastException            if the object cannot be added due to its type
++         * @throws NullPointerException          if the object cannot be added because its null
++         * @throws IllegalArgumentException      if the object cannot be added
++         */
++        public boolean add(CompositeCollection<? extends E> composite, Collection<? extends E>[] collections, Object obj);
++
++        /**
++         * Called when a collection is to be added to the composite.
++         *
++         * @param composite   the CompositeCollection being changed
++         * @param collections all of the Collection instances in this CompositeCollection
++         * @param coll        the collection being added
++         * @return true if the collection is changed
++         * @throws UnsupportedOperationException if add is unsupported
++         * @throws ClassCastException            if the object cannot be added due to its type
++         * @throws NullPointerException          if the object cannot be added because its null
++         * @throws IllegalArgumentException      if the object cannot be added
++         */
++        public boolean addAll(CompositeCollection<? extends E> composite, Collection<? extends E>[] collections, Collection<? extends E> coll);
++
++        /**
++         * Called when an object is to be removed to the composite.
++         *
++         * @param composite   the CompositeCollection being changed
++         * @param collections all of the Collection instances in this CompositeCollection
++         * @param obj         the object being removed
++         * @return true if the collection is changed
++         * @throws UnsupportedOperationException if removed is unsupported
++         * @throws ClassCastException            if the object cannot be removed due to its type
++         * @throws NullPointerException          if the object cannot be removed because its null
++         * @throws IllegalArgumentException      if the object cannot be removed
++         */
++        public boolean remove(CompositeCollection<? extends E> composite, Collection<? extends E>[] collections, Object obj);
++
++    }
++
++}
++
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/collection/PredicatedCollection.java
+@@ -0,0 +1,138 @@
++// GenericsNotes: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.collection;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.util.Collection;
++import java.util.Iterator;
++
++/**
++ * Decorates another <code>Collection</code> to validate that additions
++ * match a specified predicate.
++ * <p/>
++ * This collection exists to provide validation for the decorated collection.
++ * It is normally created to decorate an empty collection.
++ * If an object cannot be added to the collection, an IllegalArgumentException is thrown.
++ * <p/>
++ * One usage would be to ensure that no null entries are added to the collection.
++ * <pre>Collection coll = PredicatedCollection.decorate(new ArrayList(), NotNullPredicate.INSTANCE);</pre>
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public class PredicatedCollection <E> extends AbstractSerializableCollectionDecorator<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -5259182142076705162L;
++
++    /**
++     * The predicate to use
++     */
++    protected final Predicate<? super E> predicate;
++
++    /**
++     * Factory method to create a predicated (validating) collection.
++     * <p/>
++     * If there are any elements already in the collection being decorated, they
++     * are validated.
++     *
++     * @param coll      the collection to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @return a new predicated collection
++     * @throws IllegalArgumentException if collection or predicate is null
++     * @throws IllegalArgumentException if the collection contains invalid elements
++     */
++    public static <E> Collection<E> decorate(Collection<E> coll, Predicate<? super E> predicate) {
++        return new PredicatedCollection(coll, predicate);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the collection being decorated, they
++     * are validated.
++     *
++     * @param coll      the collection to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @throws IllegalArgumentException if collection or predicate is null
++     * @throws IllegalArgumentException if the collection contains invalid elements
++     */
++    protected PredicatedCollection(Collection<E> coll, Predicate<? super E> predicate) {
++        super(coll);
++        if (predicate == null) {
++            throw new IllegalArgumentException("Predicate must not be null");
++        }
++        this.predicate = predicate;
++        for (Iterator<E> it = coll.iterator(); it.hasNext();) {
++            validate(it.next());
++        }
++    }
++
++    /**
++     * Validates the object being added to ensure it matches the predicate.
++     * <p/>
++     * The predicate itself should not throw an exception, but return false to
++     * indicate that the object cannot be added.
++     *
++     * @param object the object being added
++     * @throws IllegalArgumentException if the add is invalid
++     */
++    protected void validate(E object) {
++        if (predicate.evaluate(object) == false) {
++            throw new IllegalArgumentException("Cannot add Object '" + object + "' - Predicate rejected it");
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Override to validate the object being added to ensure it matches
++     * the predicate.
++     *
++     * @param object the object being added
++     * @return the result of adding to the underlying collection
++     * @throws IllegalArgumentException if the add is invalid
++     */
++    public boolean add(E object) {
++        validate(object);
++        return getCollection().add(object);
++    }
++
++    /**
++     * Override to validate the objects being added to ensure they match
++     * the predicate. If any one fails, no update is made to the underlying
++     * collection.
++     *
++     * @param coll the collection being added
++     * @return the result of adding to the underlying collection
++     * @throws IllegalArgumentException if the add is invalid
++     */
++    public boolean addAll(Collection<? extends E> coll) {
++        for (Iterator<? extends E> it = coll.iterator(); it.hasNext();) {
++            validate(it.next());
++        }
++        return getCollection().addAll(coll);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/collection/SynchronizedCollection.java
+@@ -0,0 +1,206 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.collection;
++
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Iterator;
++
++/**
++ * Decorates another <code>Collection</code> to synchronize its behaviour
++ * for a multi-threaded environment.
++ * <p/>
++ * Iterators must be manually synchronized:
++ * <pre>
++ * synchronized (coll) {
++ *   Iterator it = coll.iterator();
++ *   // do stuff with iterator
++ * }
++ * </pre>
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public class SynchronizedCollection <E> implements Collection<E>, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 2412805092710877986L;
++
++    /**
++     * The collection to decorate
++     */
++    protected final Collection<E> collection;
++    /**
++     * The object to lock on, needed for List/SortedSet views
++     */
++    protected final Object lock;
++
++    /**
++     * Factory method to create a synchronized collection.
++     *
++     * @param coll the collection to decorate, must not be null
++     * @return a new synchronized collection
++     * @throws IllegalArgumentException if collection is null
++     */
++    public static <E> Collection<E> decorate(Collection<E> coll) {
++        return new SynchronizedCollection<E>(coll);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param collection the collection to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    protected SynchronizedCollection(Collection<E> collection) {
++        if (collection == null) {
++            throw new IllegalArgumentException("Collection must not be null");
++        }
++        this.collection = collection;
++        this.lock = this;
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param collection the collection to decorate, must not be null
++     * @param lock       the lock object to use, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    protected SynchronizedCollection(Collection<E> collection, Object lock) {
++        if (collection == null) {
++            throw new IllegalArgumentException("Collection must not be null");
++        }
++        this.collection = collection;
++        this.lock = lock;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(E object) {
++        synchronized (lock) {
++            return collection.add(object);
++        }
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        synchronized (lock) {
++            return collection.addAll(coll);
++        }
++    }
++
++    public void clear() {
++        synchronized (lock) {
++            collection.clear();
++        }
++    }
++
++    public boolean contains(Object object) {
++        synchronized (lock) {
++            return collection.contains(object);
++        }
++    }
++
++    public boolean containsAll(Collection<?> coll) {
++        synchronized (lock) {
++            return collection.containsAll(coll);
++        }
++    }
++
++    public boolean isEmpty() {
++        synchronized (lock) {
++            return collection.isEmpty();
++        }
++    }
++
++    /**
++     * Iterators must be manually synchronized.
++     * <pre>
++     * synchronized (coll) {
++     *   Iterator it = coll.iterator();
++     *   // do stuff with iterator
++     * }
++     *
++     * @return an iterator that must be manually synchronized on the collection
++     */
++    public Iterator<E> iterator() {
++        return collection.iterator();
++    }
++
++    public Object[] toArray() {
++        synchronized (lock) {
++            return collection.toArray();
++        }
++    }
++
++    public <T> T[] toArray(T[] object) {
++        synchronized (lock) {
++            return collection.toArray(object);
++        }
++    }
++
++    public boolean remove(Object object) {
++        synchronized (lock) {
++            return collection.remove(object);
++        }
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        synchronized (lock) {
++            return collection.removeAll(coll);
++        }
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        synchronized (lock) {
++            return collection.retainAll(coll);
++        }
++    }
++
++    public int size() {
++        synchronized (lock) {
++            return collection.size();
++        }
++    }
++
++    public boolean equals(Object object) {
++        synchronized (lock) {
++            if (object == this) {
++                return true;
++            }
++            return collection.equals(object);
++        }
++    }
++
++    public int hashCode() {
++        synchronized (lock) {
++            return collection.hashCode();
++        }
++    }
++
++    public String toString() {
++        synchronized (lock) {
++            return collection.toString();
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/collection/TransformedCollection.java
+@@ -0,0 +1,141 @@
++// GenericsNote: Converted, but unfortunately very little type-safety could be achieved without breaking Collection interface.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.collection;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.util.ArrayList;
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.List;
++
++/**
++ * Decorates another <code>Collection</code> to transform objects that are added.
++ * <p/>
++ * The add methods are affected by this class.
++ * Thus objects must be removed or searched for using their transformed form.
++ * For example, if the transformation converts Strings to Integers, you must
++ * use the Integer form to remove objects.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ * <p>
++ * Note: This class cannot support generics without breaking the Collection contract.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public class TransformedCollection <I,O> extends AbstractSerializableCollectionDecorator {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 8692300188161871514L;
++
++    /**
++     * The transformer to use
++     */
++    protected final Transformer<? super I, ? extends O> transformer;
++
++    /**
++     * Factory method to create a transforming collection.
++     * <p/>
++     * If there are any elements already in the collection being decorated, they
++     * are NOT transformed.
++     *
++     * @param coll        the collection to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @return a new transformed collection
++     * @throws IllegalArgumentException if collection or transformer is null
++     */
++    public static <I,O> Collection<O> decorate(Collection<I> coll, Transformer<? super I, ? extends O> transformer) {
++        return new TransformedCollection<I, O>(coll, transformer);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the collection being decorated, they
++     * are NOT transformed.
++     *
++     * @param coll        the collection to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @throws IllegalArgumentException if collection or transformer is null
++     */
++    protected TransformedCollection(Collection<I> coll, Transformer<? super I, ? extends O> transformer) {
++        super(coll);
++        if (transformer == null) {
++            throw new IllegalArgumentException("Transformer must not be null");
++        }
++        this.transformer = transformer;
++    }
++
++    /**
++     * Transforms an object.
++     * <p/>
++     * The transformer itself may throw an exception if necessary.
++     *
++     * @param object the object to transform
++     * @return a transformed object
++     */
++    protected O transform(I object) {
++        return transformer.transform(object);
++    }
++
++    /**
++     * Transforms a collection.
++     * <p/>
++     * The transformer itself may throw an exception if necessary.
++     *
++     * @param coll the collection to transform
++     * @return a transformed object
++     */
++    protected Collection<O> transform(Collection<? extends I> coll) {
++        List<O> list = new ArrayList<O>(coll.size());
++        for (Iterator<? extends I> it = coll.iterator(); it.hasNext();) {
++            list.add(transform(it.next()));
++        }
++        return list;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(Object object) {
++        O transformed = transform((I) object);
++        return getCollection().add(transformed);
++    }
++
++    /**
++     * A better typed version of the add method (although breaks the Collection interface).
++     */
++    public boolean addTyped(I object) {
++        return add(object);
++    }
++
++    public boolean addAll(Collection coll) {
++        Collection<O> col2 = transform((Collection<? extends I>) coll);
++        return getCollection().addAll(col2);
++    }
++
++    /**
++     * A better typed version of the addAll method (although breaks the Collection interface).
++     */
++    public boolean addAllTyped(Collection<? extends I> coll) {
++        return addAll(coll);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/collection/TypedCollection.java
+@@ -0,0 +1,61 @@
++// GenericsNote: Not converted, deprecated.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.collection;
++
++import org.apache.commons.collections15.functors.InstanceofPredicate;
++
++import java.util.Collection;
++
++/**
++ * Decorates a <code>Collection</code> to validate that elements added are of a specific type.
++ * <p/>
++ * The validation of additions is performed via an instanceof test against
++ * a specified <code>Class</code>. If an object cannot be added to the
++ * collection, an IllegalArgumentException is thrown.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ * @deprecated Type safe classes are no longer required under 1.5.
++ */
++public class TypedCollection {
++
++    /**
++     * Factory method to create a typed collection.
++     * <p/>
++     * If there are any elements already in the collection being decorated, they
++     * are validated.
++     *
++     * @param coll the collection to decorate, must not be null
++     * @param type the type to allow into the collection, must not be null
++     * @return a new typed collection
++     * @throws IllegalArgumentException if collection or type is null
++     * @throws IllegalArgumentException if the collection contains invalid elements
++     */
++    public static Collection decorate(Collection coll, Class type) {
++        return new PredicatedCollection(coll, InstanceofPredicate.getInstance(type));
++    }
++
++    /**
++     * Restrictive constructor.
++     */
++    protected TypedCollection() {
++        super();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/collection/UnmodifiableBoundedCollection.java
+@@ -0,0 +1,141 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.collection;
++
++import org.apache.commons.collections15.BoundedCollection;
++import org.apache.commons.collections15.iterators.UnmodifiableIterator;
++
++import java.util.Collection;
++import java.util.Iterator;
++
++/**
++ * <code>UnmodifiableBoundedCollection</code> decorates another
++ * <code>BoundedCollection</code> to ensure it can't be altered.
++ * <p/>
++ * If a BoundedCollection is first wrapped in some other collection decorator,
++ * such as synchronized or predicated, the BoundedCollection methods are no
++ * longer accessible.
++ * The factory on this class will attempt to retrieve the bounded nature by
++ * examining the package scope variables.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableBoundedCollection <E> extends AbstractSerializableCollectionDecorator<E> implements BoundedCollection<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -7112672385450340330L;
++
++    /**
++     * Factory method to create an unmodifiable bounded collection.
++     *
++     * @param coll the <code>BoundedCollection</code> to decorate, must not be null
++     * @return a new unmodifiable bounded collection
++     * @throws IllegalArgumentException if bag is null
++     */
++    public static <E> BoundedCollection<E> decorate(BoundedCollection<E> coll) {
++        return new UnmodifiableBoundedCollection<E>(coll);
++    }
++
++    /**
++     * Factory method to create an unmodifiable bounded collection.
++     * <p/>
++     * This method is capable of drilling down through up to 1000 other decorators
++     * to find a suitable BoundedCollection.
++     *
++     * @param coll the <code>BoundedCollection</code> to decorate, must not be null
++     * @return a new unmodifiable bounded collection
++     * @throws IllegalArgumentException if bag is null
++     */
++    public static <E> BoundedCollection<E> decorateUsing(Collection<E> coll) {
++        if (coll == null) {
++            throw new IllegalArgumentException("The collection must not be null");
++        }
++        
++        // handle decorators
++        for (int i = 0; i < 1000; i++) {  // counter to prevent infinite looping
++            if (coll instanceof BoundedCollection) {
++                break;  // normal loop exit
++            } else if (coll instanceof AbstractCollectionDecorator) {
++                coll = ((AbstractCollectionDecorator<E>) coll).collection;
++            } else if (coll instanceof SynchronizedCollection) {
++                coll = ((SynchronizedCollection<E>) coll).collection;
++            } else {
++                break;  // normal loop exit
++            }
++        }
++
++        if (coll instanceof BoundedCollection == false) {
++            throw new IllegalArgumentException("The collection is not a bounded collection");
++        }
++        return new UnmodifiableBoundedCollection<E>((BoundedCollection) coll);
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param coll the collection to decorate, must not be null
++     * @throws IllegalArgumentException if coll is null
++     */
++    private UnmodifiableBoundedCollection(BoundedCollection<E> coll) {
++        super(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    public Iterator<E> iterator() {
++        return UnmodifiableIterator.decorate(getCollection().iterator());
++    }
++
++    public boolean add(E object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean remove(Object object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    //-----------------------------------------------------------------------    
++    public boolean isFull() {
++        return ((BoundedCollection) collection).isFull();
++    }
++
++    public int maxSize() {
++        return ((BoundedCollection) collection).maxSize();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/collection/UnmodifiableCollection.java
+@@ -0,0 +1,97 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.collection;
++
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.iterators.UnmodifiableIterator;
++
++import java.util.Collection;
++import java.util.Iterator;
++
++/**
++ * Decorates another <code>Collection</code> to ensure it can't be altered.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableCollection <E> extends AbstractSerializableCollectionDecorator<E> implements Unmodifiable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -239892006883819945L;
++
++    /**
++     * Factory method to create an unmodifiable collection.
++     * <p/>
++     * If the collection passed in is already unmodifiable, it is returned.
++     *
++     * @param coll the collection to decorate, must not be null
++     * @return an unmodifiable collection
++     * @throws IllegalArgumentException if collection is null
++     */
++    public static <E> Collection<E> decorate(Collection<E> coll) {
++        if (coll instanceof Unmodifiable) {
++            return coll;
++        }
++        return new UnmodifiableCollection<E>(coll);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param coll the collection to decorate, must not be null
++     * @throws IllegalArgumentException if collection is null
++     */
++    private UnmodifiableCollection(Collection<E> coll) {
++        super(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    public Iterator<E> iterator() {
++        return UnmodifiableIterator.decorate(getCollection().iterator());
++    }
++
++    public boolean add(E object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean remove(Object object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/collection/package.html
+@@ -0,0 +1,35 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:20 pents90 Exp $ -->
++ <!--
++   Copyright 2003-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<BODY>
++<p>
++This package contains implementations of the
++{@link java.util.Collection Collection} interface.
++<p>
++The following implementations are provided in the package:
++<ul>
++<li>CompositeCollection - a collection that combines multiple collections into one
++</ul>
++The following decorators are provided in the package:
++<ul>
++<li>Synchronized - synchronizes method access for multi-threaded environments
++<li>Unmodifiable - ensures the collection cannot be altered
++<li>Predicated - ensures that only elements that are valid according to a predicate can be added
++<li>Typed - ensures that only elements that are of a specific type can be added
++<li>Transformed - transforms elements as they are added
++</ul>
++</pre>
++</BODY>
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/comparators/BooleanComparator.java
+@@ -0,0 +1,194 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.comparators;
++
++import java.io.Serializable;
++import java.util.Comparator;
++
++/**
++ * A {@link Comparator} for {@link Boolean} objects that can sort either
++ * true or false first.
++ * <p/>
++ *
++ * @author Matt Hall, John Watkinson, Rodney Waldhoff
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @see #getTrueFirstComparator()
++ * @see #getFalseFirstComparator()
++ * @see #getBooleanComparator(boolean)
++ * @since Commons Collections 3.0
++ */
++public final class BooleanComparator implements Comparator<Boolean>, Serializable {
++
++    /**
++     * Serialization version.
++     */
++    private static final long serialVersionUID = 1830042991606340609L;
++
++    /**
++     * Constant "true first" reference.
++     */
++    private static final BooleanComparator TRUE_FIRST = new BooleanComparator(true);
++
++    /**
++     * Constant "false first" reference.
++     */
++    private static final BooleanComparator FALSE_FIRST = new BooleanComparator(false);
++
++    /**
++     * <code>true</code> iff <code>true</code> values sort before <code>false</code> values.
++     */
++    private boolean trueFirst = false;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a BooleanComparator instance that sorts
++     * <code>true</code> values before <code>false</code> values.
++     * <p />
++     * Clients are encouraged to use the value returned from
++     * this method instead of constructing a new instance
++     * to reduce allocation and garbage collection overhead when
++     * multiple BooleanComparators may be used in the same
++     * virtual machine.
++     *
++     * @return the true first singleton BooleanComparator
++     */
++    public static BooleanComparator getTrueFirstComparator() {
++        return TRUE_FIRST;
++    }
++
++    /**
++     * Returns a BooleanComparator instance that sorts
++     * <code>false</code> values before <code>true</code> values.
++     * <p />
++     * Clients are encouraged to use the value returned from
++     * this method instead of constructing a new instance
++     * to reduce allocation and garbage collection overhead when
++     * multiple BooleanComparators may be used in the same
++     * virtual machine.
++     *
++     * @return the false first singleton BooleanComparator
++     */
++    public static BooleanComparator getFalseFirstComparator() {
++        return FALSE_FIRST;
++    }
++
++    /**
++     * Returns a BooleanComparator instance that sorts
++     * <code><i>trueFirst</i></code> values before
++     * <code>&#x21;<i>trueFirst</i></code> values.
++     * <p />
++     * Clients are encouraged to use the value returned from
++     * this method instead of constructing a new instance
++     * to reduce allocation and garbage collection overhead when
++     * multiple BooleanComparators may be used in the same
++     * virtual machine.
++     *
++     * @param trueFirst when <code>true</code>, sort
++     *                  <code>true</code> <code>Boolean</code>s before <code>false</code>
++     * @return a singleton BooleanComparator instance
++     */
++    public static BooleanComparator getBooleanComparator(boolean trueFirst) {
++        return trueFirst ? TRUE_FIRST : FALSE_FIRST;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Creates a <code>BooleanComparator</code> that sorts
++     * <code>false</code> values before <code>true</code> values.
++     * <p/>
++     * Equivalent to {@link #BooleanComparator(boolean) BooleanComparator(false)}.
++     * <p/>
++     * Please use the static factory instead whenever possible.
++     */
++    public BooleanComparator() {
++        this(false);
++    }
++
++    /**
++     * Creates a <code>BooleanComparator</code> that sorts
++     * <code><i>trueFirst</i></code> values before
++     * <code>&#x21;<i>trueFirst</i></code> values.
++     * <p/>
++     * Please use the static factories instead whenever possible.
++     *
++     * @param trueFirst when <code>true</code>, sort
++     *                  <code>true</code> boolean values before <code>false</code>
++     */
++    public BooleanComparator(boolean trueFirst) {
++        this.trueFirst = trueFirst;
++    }
++
++    /**
++     * Compares two non-<code>null</code> <code>Boolean</code> objects
++     * according to the value of {@link #trueFirst}.
++     *
++     * @param b1 the first boolean to compare
++     * @param b2 the second boolean to compare
++     * @return negative if obj1 is less, positive if greater, zero if equal
++     * @throws NullPointerException when either argument <code>null</code>
++     */
++    public int compare(Boolean b1, Boolean b2) {
++        boolean v1 = b1.booleanValue();
++        boolean v2 = b2.booleanValue();
++
++        return (v1 ^ v2) ? ((v1 ^ trueFirst) ? 1 : -1) : 0;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Implement a hash code for this comparator that is consistent with
++     * {@link #equals(Object) equals}.
++     *
++     * @return a hash code for this comparator.
++     */
++    public int hashCode() {
++        int hash = "BooleanComparator".hashCode();
++        return trueFirst ? -1 * hash : hash;
++    }
++
++    /**
++     * Returns <code>true</code> iff <i>that</i> Object is
++     * is a {@link Comparator} whose ordering is known to be
++     * equivalent to mine.
++     * <p/>
++     * This implementation returns <code>true</code>
++     * iff <code><i>that</i></code> is a {@link BooleanComparator}
++     * whose {@link #trueFirst} value is equal to mine.
++     *
++     * @param object the object to compare to
++     * @return true if equal
++     */
++    public boolean equals(Object object) {
++        return (this == object) || ((object instanceof BooleanComparator) && (this.trueFirst == ((BooleanComparator) object).trueFirst));
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns <code>true</code> iff
++     * I sort <code>true</code> values before
++     * <code>false</code> values.  In other words,
++     * returns <code>true</code> iff
++     * {@link #compare(Boolean,Boolean) compare(Boolean.FALSE,Boolean.TRUE)}
++     * returns a positive value.
++     *
++     * @return the trueFirst flag
++     */
++    public boolean sortsTrueFirst() {
++        return trueFirst;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/comparators/ComparableComparator.java
+@@ -0,0 +1,128 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.comparators;
++
++import java.io.Serializable;
++import java.util.Comparator;
++
++/**
++ * A {@link Comparator Comparator} that compares
++ * {@link Comparable Comparable} objects.
++ * <p />
++ * This Comparator is useful, for example,
++ * for enforcing the natural order in custom implementations
++ * of SortedSet and SortedMap.
++ * <p />
++ * Note: In the 2.0 and 2.1 releases of Commons Collections,
++ * this class would throw a {@link ClassCastException} if
++ * either of the arguments to {@link #compare(Object, Object) compare}
++ * were <code>null</code>, not {@link Comparable Comparable},
++ * or for which {@link Comparable#compareTo(Object) compareTo} gave
++ * inconsistent results.  This is no longer the case.  See
++ * {@link #compare(Object, Object) compare} for details.
++ *
++ * @author Matt Hall, John Watkinson, Henri Yandell
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @see java.util.Collections#reverseOrder()
++ * @since Commons Collections 2.0
++ */
++public class ComparableComparator<T extends Comparable> implements Comparator<T>, Serializable {
++
++    /**
++     * Serialization version.
++     */
++    private static final long serialVersionUID = -291439688585137865L;
++
++    /**
++     * The singleton instance.
++     */
++    private static final ComparableComparator instance = new ComparableComparator();
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the singleton instance of a ComparableComparator.
++     * <p/>
++     * Developers are encouraged to use the comparator returned from this method
++     * instead of constructing a new instance to reduce allocation and GC overhead
++     * when multiple comparable comparators may be used in the same VM.
++     *
++     * @return the singleton ComparableComparator
++     */
++	public static <T> Comparator<T> getInstance() {
++        return instance;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor whose use should be avoided.
++     * <p/>
++     * Please use the {@link #getInstance()} method whenever possible.
++     */
++    public ComparableComparator() {
++        super();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Compare the two {@link Comparable Comparable} arguments.
++     * This method is equivalent to:
++     * <pre>((Comparable)obj1).compareTo(obj2)</pre>
++     *
++     * @param obj1 the first object to compare
++     * @param obj2 the second object to compare
++     * @return negative if obj1 is less, positive if greater, zero if equal
++     * @throws NullPointerException when <i>obj1</i> is <code>null</code>,
++     *                              or when <code>((Comparable)obj1).compareTo(obj2)</code> does
++     * @throws ClassCastException   when <i>obj1</i> is not a <code>Comparable</code>,
++     *                              or when <code>((Comparable)obj1).compareTo(obj2)</code> does
++     */
++    public int compare(T obj1, T obj2) {
++        return obj1.compareTo(obj2);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Implement a hash code for this comparator that is consistent with
++     * {@link #equals(Object) equals}.
++     *
++     * @return a hash code for this comparator.
++     * @since Commons Collections 3.0
++     */
++    public int hashCode() {
++        return "ComparableComparator".hashCode();
++    }
++
++    /**
++     * Returns <code>true</code> iff <i>that</i> Object is
++     * is a {@link Comparator Comparator} whose ordering is
++     * known to be equivalent to mine.
++     * <p/>
++     * This implementation returns <code>true</code>
++     * iff <code><i>object</i>.{@link Object#getClass() getClass()}</code>
++     * equals <code>this.getClass()</code>.
++     * Subclasses may want to override this behavior to remain consistent
++     * with the {@link Comparator#equals(Object)} contract.
++     *
++     * @param object the object to compare with
++     * @return true if equal
++     * @since Commons Collections 3.0
++     */
++    public boolean equals(Object object) {
++        return (this == object) || ((null != object) && (object.getClass().equals(this.getClass())));
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/comparators/ComparatorChain.java
+@@ -0,0 +1,347 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.comparators;
++
++import java.io.Serializable;
++import java.util.*;
++
++/**
++ * <p>A ComparatorChain is a Comparator that wraps one or
++ * more Comparators in sequence.  The ComparatorChain
++ * calls each Comparator in sequence until either 1)
++ * any single Comparator returns a non-zero result
++ * (and that result is then returned),
++ * or 2) the ComparatorChain is exhausted (and zero is
++ * returned).  This type of sorting is very similar
++ * to multi-column sorting in SQL, and this class
++ * allows Java classes to emulate that kind of behaviour
++ * when sorting a List.</p>
++ * <p/>
++ * <p>To further facilitate SQL-like sorting, the order of
++ * any single Comparator in the list can be reversed.</p>
++ * <p/>
++ * <p>Calling a method that adds new Comparators or
++ * changes the ascend/descend sort <i>after compare(Object,
++ * Object) has been called</i> will result in an
++ * UnsupportedOperationException.  However, <i>take care</i>
++ * to not alter the underlying List of Comparators
++ * or the BitSet that defines the sort order.</p>
++ * <p/>
++ * <p>Instances of ComparatorChain are not synchronized.
++ * The class is not thread-safe at construction time, but
++ * it <i>is</i> thread-safe to perform multiple comparisons
++ * after all the setup operations are complete.</p>
++ *
++ * @author Matt Hall, John Watkinson, Morgan Delagrange
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 2.0
++ */
++public class ComparatorChain <T> implements Comparator<T>, Serializable {
++
++    /**
++     * Serialization version from Collections 2.0.
++     */
++    private static final long serialVersionUID = -721644942746081630L;
++
++    /**
++     * The list of comparators in the chain.
++     */
++    protected List<Comparator<T>> comparatorChain = null;
++    /**
++     * Order - false (clear) = ascend; true (set) = descend.
++     */
++    protected BitSet orderingBits = null;
++    /**
++     * Whether the chain has been "locked".
++     */
++    protected boolean isLocked = false;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Construct a ComparatorChain with no Comparators.
++     * You must add at least one Comparator before calling
++     * the compare(Object,Object) method, or an
++     * UnsupportedOperationException is thrown
++     */
++    public ComparatorChain() {
++        this(new ArrayList<Comparator<T>>(), new BitSet());
++    }
++
++    /**
++     * Construct a ComparatorChain with a single Comparator,
++     * sorting in the forward order
++     *
++     * @param comparator First comparator in the Comparator chain
++     */
++    public ComparatorChain(Comparator<T> comparator) {
++        this(comparator, false);
++    }
++
++    /**
++     * Construct a Comparator chain with a single Comparator,
++     * sorting in the given order
++     *
++     * @param comparator First Comparator in the ComparatorChain
++     * @param reverse    false = forward sort; true = reverse sort
++     */
++    public ComparatorChain(Comparator<T> comparator, boolean reverse) {
++        comparatorChain = new ArrayList<Comparator<T>>();
++        comparatorChain.add(comparator);
++        orderingBits = new BitSet(1);
++        if (reverse == true) {
++            orderingBits.set(0);
++        }
++    }
++
++    /**
++     * Construct a ComparatorChain from the Comparators in the
++     * List.  All Comparators will default to the forward
++     * sort order.
++     *
++     * @param list List of Comparators
++     * @see #ComparatorChain(List,BitSet)
++     */
++    public ComparatorChain(List<Comparator<T>> list) {
++        this(list, new BitSet(list.size()));
++    }
++
++    /**
++     * Construct a ComparatorChain from the Comparators in the
++     * given List.  The sort order of each column will be
++     * drawn from the given BitSet.  When determining the sort
++     * order for Comparator at index <i>i</i> in the List,
++     * the ComparatorChain will call BitSet.get(<i>i</i>).
++     * If that method returns <i>false</i>, the forward
++     * sort order is used; a return value of <i>true</i>
++     * indicates reverse sort order.
++     *
++     * @param list List of Comparators.  NOTE: This constructor does not perform a
++     *             defensive copy of the list
++     * @param bits Sort order for each Comparator.  Extra bits are ignored,
++     *             unless extra Comparators are added by another method.
++     */
++    public ComparatorChain(List<Comparator<T>> list, BitSet bits) {
++        comparatorChain = list;
++        orderingBits = bits;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Add a Comparator to the end of the chain using the
++     * forward sort order
++     *
++     * @param comparator Comparator with the forward sort order
++     */
++    public void addComparator(Comparator<T> comparator) {
++        addComparator(comparator, false);
++    }
++
++    /**
++     * Add a Comparator to the end of the chain using the
++     * given sort order
++     *
++     * @param comparator Comparator to add to the end of the chain
++     * @param reverse    false = forward sort order; true = reverse sort order
++     */
++    public void addComparator(Comparator<T> comparator, boolean reverse) {
++        checkLocked();
++
++        comparatorChain.add(comparator);
++        if (reverse == true) {
++            orderingBits.set(comparatorChain.size() - 1);
++        }
++    }
++
++    /**
++     * Replace the Comparator at the given index, maintaining
++     * the existing sort order.
++     *
++     * @param index      index of the Comparator to replace
++     * @param comparator Comparator to place at the given index
++     * @throws IndexOutOfBoundsException if index < 0 or index >= size()
++     */
++    public void setComparator(int index, Comparator<T> comparator) throws IndexOutOfBoundsException {
++        setComparator(index, comparator, false);
++    }
++
++    /**
++     * Replace the Comparator at the given index in the
++     * ComparatorChain, using the given sort order
++     *
++     * @param index      index of the Comparator to replace
++     * @param comparator Comparator to set
++     * @param reverse    false = forward sort order; true = reverse sort order
++     */
++    public void setComparator(int index, Comparator<T> comparator, boolean reverse) {
++        checkLocked();
++
++        comparatorChain.set(index, comparator);
++        if (reverse == true) {
++            orderingBits.set(index);
++        } else {
++            orderingBits.clear(index);
++        }
++    }
++
++
++    /**
++     * Change the sort order at the given index in the
++     * ComparatorChain to a forward sort.
++     *
++     * @param index Index of the ComparatorChain
++     */
++    public void setForwardSort(int index) {
++        checkLocked();
++        orderingBits.clear(index);
++    }
++
++    /**
++     * Change the sort order at the given index in the
++     * ComparatorChain to a reverse sort.
++     *
++     * @param index Index of the ComparatorChain
++     */
++    public void setReverseSort(int index) {
++        checkLocked();
++        orderingBits.set(index);
++    }
++
++    /**
++     * Number of Comparators in the current ComparatorChain.
++     *
++     * @return Comparator count
++     */
++    public int size() {
++        return comparatorChain.size();
++    }
++
++    /**
++     * Determine if modifications can still be made to the
++     * ComparatorChain.  ComparatorChains cannot be modified
++     * once they have performed a comparison.
++     *
++     * @return true = ComparatorChain cannot be modified; false =
++     *         ComparatorChain can still be modified.
++     */
++    public boolean isLocked() {
++        return isLocked;
++    }
++
++    // throw an exception if the ComparatorChain is locked
++    private void checkLocked() {
++        if (isLocked == true) {
++            throw new UnsupportedOperationException("Comparator ordering cannot be changed after the first comparison is performed");
++        }
++    }
++
++    private void checkChainIntegrity() {
++        if (comparatorChain.size() == 0) {
++            throw new UnsupportedOperationException("ComparatorChains must contain at least one Comparator");
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Perform comparisons on the Objects as per
++     * Comparator.compare(o1,o2).
++     *
++     * @param o1 the first object to compare
++     * @param o2 the second object to compare
++     * @return -1, 0, or 1
++     * @throws UnsupportedOperationException if the ComparatorChain does not contain at least one
++     *                                       Comparator
++     */
++    public int compare(T o1, T o2) throws UnsupportedOperationException {
++        if (isLocked == false) {
++            checkChainIntegrity();
++            isLocked = true;
++        }
++
++        // iterate over all comparators in the chain
++        Iterator<Comparator<T>> comparators = comparatorChain.iterator();
++        for (int comparatorIndex = 0; comparators.hasNext(); ++comparatorIndex) {
++
++            Comparator<T> comparator = comparators.next();
++            int retval = comparator.compare(o1, o2);
++            if (retval != 0) {
++                // invert the order if it is a reverse sort
++                if (orderingBits.get(comparatorIndex) == true) {
++                    if (Integer.MIN_VALUE == retval) {
++                        retval = Integer.MAX_VALUE;
++                    } else {
++                        retval *= -1;
++                    }
++                }
++
++                return retval;
++            }
++
++        }
++
++        // if comparators are exhausted, return 0
++        return 0;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Implement a hash code for this comparator that is consistent with
++     * {@link #equals(Object) equals}.
++     *
++     * @return a suitable hash code
++     * @since Commons Collections 3.0
++     */
++    public int hashCode() {
++        int hash = 0;
++        if (null != comparatorChain) {
++            hash ^= comparatorChain.hashCode();
++        }
++        if (null != orderingBits) {
++            hash ^= orderingBits.hashCode();
++        }
++        return hash;
++    }
++
++    /**
++     * Returns <code>true</code> iff <i>that</i> Object is
++     * is a {@link Comparator} whose ordering is known to be
++     * equivalent to mine.
++     * <p/>
++     * This implementation returns <code>true</code>
++     * iff <code><i>object</i>.{@link Object#getClass() getClass()}</code>
++     * equals <code>this.getClass()</code>, and the underlying
++     * comparators and order bits are equal.
++     * Subclasses may want to override this behavior to remain consistent
++     * with the {@link Comparator#equals(Object)} contract.
++     *
++     * @param object the object to compare with
++     * @return true if equal
++     * @since Commons Collections 3.0
++     */
++    public boolean equals(Object object) {
++        if (this == object) {
++            return true;
++        } else if (null == object) {
++            return false;
++        } else if (object.getClass().equals(this.getClass())) {
++            ComparatorChain chain = (ComparatorChain) object;
++            return ((null == orderingBits ? null == chain.orderingBits : orderingBits.equals(chain.orderingBits)) && (null == comparatorChain ? null == chain.comparatorChain : comparatorChain.equals(chain.comparatorChain)));
++        } else {
++            return false;
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/comparators/FixedOrderComparator.java
+@@ -0,0 +1,267 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.comparators;
++
++import java.util.*;
++
++/**
++ * A Comparator which imposes a specific order on a specific set of Objects.
++ * Objects are presented to the FixedOrderComparator in a specified order and
++ * subsequent calls to {@link #compare(Object, Object) compare} yield that order.
++ * For example:
++ * <pre>
++ * String[] planets = {"Mercury", "Venus", "Earth", "Mars"};
++ * FixedOrderComparator distanceFromSun = new FixedOrderComparator(planets);
++ * Arrays.sort(planets);                     // Sort to alphabetical order
++ * Arrays.sort(planets, distanceFromSun);    // Back to original order
++ * </pre>
++ * <p/>
++ * Once <code>compare</code> has been called, the FixedOrderComparator is locked
++ * and attempts to modify it yield an UnsupportedOperationException.
++ * <p/>
++ * Instances of FixedOrderComparator are not synchronized.  The class is not
++ * thread-safe at construction time, but it is thread-safe to perform
++ * multiple comparisons  after all the setup operations are complete.
++ *
++ * @author David Leppik
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Janek Bogucki
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 3.0
++ */
++public class FixedOrderComparator <T> implements Comparator<T> {
++
++    /**
++     * Behavior when comparing unknown Objects:
++     * unknown objects compare as before known Objects.
++     */
++    public static final int UNKNOWN_BEFORE = 0;
++
++    /**
++     * Behavior when comparing unknown Objects:
++     * unknown objects compare as after known Objects.
++     */
++    public static final int UNKNOWN_AFTER = 1;
++
++    /**
++     * Behavior when comparing unknown Objects:
++     * unknown objects cause a IllegalArgumentException to be thrown.
++     * This is the default behavior.
++     */
++    public static final int UNKNOWN_THROW_EXCEPTION = 2;
++
++    /**
++     * Internal map of object to position
++     */
++    private final Map<T, Integer> map = new HashMap<T, Integer>();
++    /**
++     * Counter used in determining the position in the map
++     */
++    private int counter = 0;
++    /**
++     * Is the comparator locked against further change
++     */
++    private boolean isLocked = false;
++    /**
++     * The behaviour in the case of an unknown object
++     */
++    private int unknownObjectBehavior = UNKNOWN_THROW_EXCEPTION;
++
++    // Constructors
++    //-----------------------------------------------------------------------
++    /**
++     * Constructs an empty FixedOrderComparator.
++     */
++    public FixedOrderComparator() {
++        super();
++    }
++
++    /**
++     * Constructs a FixedOrderComparator which uses the order of the given array
++     * to compare the objects.
++     * <p/>
++     * The array is copied, so later changes will not affect the comparator.
++     *
++     * @param items the items that the comparator can compare in order
++     * @throws IllegalArgumentException if the array is null
++     */
++    public FixedOrderComparator(T[] items) {
++        super();
++        if (items == null) {
++            throw new IllegalArgumentException("The list of items must not be null");
++        }
++        for (int i = 0; i < items.length; i++) {
++            add(items[i]);
++        }
++    }
++
++    /**
++     * Constructs a FixedOrderComparator which uses the order of the given list
++     * to compare the objects.
++     * <p/>
++     * The list is copied, so later changes will not affect the comparator.
++     *
++     * @param items the items that the comparator can compare in order
++     * @throws IllegalArgumentException if the list is null
++     */
++    public FixedOrderComparator(List<T> items) {
++        super();
++        if (items == null) {
++            throw new IllegalArgumentException("The list of items must not be null");
++        }
++        for (Iterator<T> it = items.iterator(); it.hasNext();) {
++            add(it.next());
++        }
++    }
++
++    // Bean methods / state querying methods
++    //-----------------------------------------------------------------------
++    /**
++     * Returns true if modifications cannot be made to the FixedOrderComparator.
++     * FixedOrderComparators cannot be modified once they have performed a comparison.
++     *
++     * @return true if attempts to change the FixedOrderComparator yield an
++     *         UnsupportedOperationException, false if it can be changed.
++     */
++    public boolean isLocked() {
++        return isLocked;
++    }
++
++    /**
++     * Checks to see whether the comparator is now locked against further changes.
++     *
++     * @throws UnsupportedOperationException if the comparator is locked
++     */
++    protected void checkLocked() {
++        if (isLocked()) {
++            throw new UnsupportedOperationException("Cannot modify a FixedOrderComparator after a comparison");
++        }
++    }
++
++    /**
++     * Gets the behavior for comparing unknown objects.
++     *
++     * @return the flag for unknown behaviour - UNKNOWN_AFTER,
++     *         UNKNOWN_BEFORE or UNKNOWN_THROW_EXCEPTION
++     */
++    public int getUnknownObjectBehavior() {
++        return unknownObjectBehavior;
++    }
++
++    /**
++     * Sets the behavior for comparing unknown objects.
++     *
++     * @param unknownObjectBehavior the flag for unknown behaviour -
++     *                              UNKNOWN_AFTER, UNKNOWN_BEFORE or UNKNOWN_THROW_EXCEPTION
++     * @throws UnsupportedOperationException if a comparison has been performed
++     * @throws IllegalArgumentException      if the unknown flag is not valid
++     */
++    public void setUnknownObjectBehavior(int unknownObjectBehavior) {
++        checkLocked();
++        if (unknownObjectBehavior != UNKNOWN_AFTER && unknownObjectBehavior != UNKNOWN_BEFORE && unknownObjectBehavior != UNKNOWN_THROW_EXCEPTION) {
++            throw new IllegalArgumentException("Unrecognised value for unknown behaviour flag");
++        }
++        this.unknownObjectBehavior = unknownObjectBehavior;
++    }
++
++    // Methods for adding items
++    //-----------------------------------------------------------------------
++    /**
++     * Adds an item, which compares as after all items known to the Comparator.
++     * If the item is already known to the Comparator, its old position is
++     * replaced with the new position.
++     *
++     * @param obj the item to be added to the Comparator.
++     * @return true if obj has been added for the first time, false if
++     *         it was already known to the Comparator.
++     * @throws UnsupportedOperationException if a comparison has already been made
++     */
++    public boolean add(T obj) {
++        checkLocked();
++        Integer position = map.put(obj, new Integer(counter++));
++        return (position == null);
++    }
++
++    /**
++     * Adds a new item, which compares as equal to the given existing item.
++     *
++     * @param existingObj an item already in the Comparator's set of
++     *                    known objects
++     * @param newObj      an item to be added to the Comparator's set of
++     *                    known objects
++     * @return true if newObj has been added for the first time, false if
++     *         it was already known to the Comparator.
++     * @throws IllegalArgumentException      if existingObject is not in the
++     *                                       Comparator's set of known objects.
++     * @throws UnsupportedOperationException if a comparison has already been made
++     */
++    public boolean addAsEqual(T existingObj, T newObj) {
++        checkLocked();
++        Integer position = (Integer) map.get(existingObj);
++        if (position == null) {
++            throw new IllegalArgumentException(existingObj + " not known to " + this);
++        }
++        Integer result = map.put(newObj, position);
++        return (result == null);
++    }
++
++    // Comparator methods
++    //-----------------------------------------------------------------------
++    /**
++     * Compares two objects according to the order of this Comparator.
++     * <p/>
++     * It is important to note that this class will throw an IllegalArgumentException
++     * in the case of an unrecognised object. This is not specified in the
++     * Comparator interface, but is the most appropriate exception.
++     *
++     * @param obj1 the first object to compare
++     * @param obj2 the second object to compare
++     * @return negative if obj1 is less, positive if greater, zero if equal
++     * @throws IllegalArgumentException if obj1 or obj2 are not known
++     *                                  to this Comparator and an alternative behavior has not been set
++     *                                  via {@link #setUnknownObjectBehavior(int)}.
++     */
++    public int compare(T obj1, T obj2) {
++        isLocked = true;
++        Integer position1 = (Integer) map.get(obj1);
++        Integer position2 = (Integer) map.get(obj2);
++        if (position1 == null || position2 == null) {
++            switch (unknownObjectBehavior) {
++                case UNKNOWN_BEFORE:
++                    if (position1 == null) {
++                        return (position2 == null) ? 0 : -1;
++                    } else {
++                        return 1;
++                    }
++                case UNKNOWN_AFTER:
++                    if (position1 == null) {
++                        return (position2 == null) ? 0 : 1;
++                    } else {
++                        return -1;
++                    }
++                case UNKNOWN_THROW_EXCEPTION:
++                    Object unknownObj = (position1 == null) ? obj1 : obj2;
++                    throw new IllegalArgumentException("Attempting to compare unknown object " + unknownObj);
++                default :
++                    throw new UnsupportedOperationException("Unknown unknownObjectBehavior: " + unknownObjectBehavior);
++            }
++        } else {
++            return position1.compareTo(position2);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/comparators/NullComparator.java
+@@ -0,0 +1,157 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.comparators;
++
++import java.io.Serializable;
++import java.util.Comparator;
++
++/**
++ * A Comparator that will compare nulls to be either lower or higher than
++ * other objects.
++ *
++ * @author Matt Hall, John Watkinson, Michael A. Smith
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @since Commons Collections 2.0
++ */
++public class NullComparator <T> implements Comparator<T>, Serializable {
++
++    /**
++     * Serialization version.
++     */
++    private static final long serialVersionUID = -5820772575483504339L;
++
++    /**
++     * The comparator to use when comparing two non-<code>null</code> objects.
++     */
++    private Comparator<T> nonNullComparator;
++
++    /**
++     * Specifies whether a <code>null</code> are compared as higher than
++     * non-<code>null</code> objects.
++     */
++    private boolean nullsAreHigh;
++
++    /**
++     * Construct an instance that sorts <code>null</code> higher than any
++     * non-<code>null</code> object it is compared with.  When comparing two
++     * non-<code>null</code> objects, the specified {@link Comparator} is
++     * used.
++     *
++     * @param nonNullComparator the comparator to use when comparing two
++     *                          non-<code>null</code> objects.  This argument cannot be
++     *                          <code>null</code>
++     * @throws NullPointerException if <code>nonNullComparator</code> is
++     *                              <code>null</code>
++     */
++    public NullComparator(Comparator<T> nonNullComparator) {
++        this(nonNullComparator, true);
++    }
++
++    /**
++     * Construct an instance that sorts <code>null</code> higher or lower than
++     * any non-<code>null</code> object it is compared with.  When comparing
++     * two non-<code>null</code> objects, the specified {@link Comparator} is
++     * used.
++     *
++     * @param nonNullComparator the comparator to use when comparing two
++     *                          non-<code>null</code> objects. This argument cannot be
++     *                          <code>null</code>
++     * @param nullsAreHigh      a <code>true</code> value indicates that
++     *                          <code>null</code> should be compared as higher than a
++     *                          non-<code>null</code> object.  A <code>false</code> value indicates
++     *                          that <code>null</code> should be compared as lower than a
++     *                          non-<code>null</code> object.
++     * @throws NullPointerException if <code>nonNullComparator</code> is
++     *                              <code>null</code>
++     */
++    public NullComparator(Comparator<T> nonNullComparator, boolean nullsAreHigh) {
++        this.nonNullComparator = nonNullComparator;
++        this.nullsAreHigh = nullsAreHigh;
++
++        if (nonNullComparator == null) {
++            throw new NullPointerException("null nonNullComparator");
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Perform a comparison between two objects.  If both objects are
++     * <code>null</code>, a <code>0</code> value is returned.  If one object
++     * is <code>null</code> and the other is not, the result is determined on
++     * whether the Comparator was constructed to have nulls as higher or lower
++     * than other objects.  If neither object is <code>null</code>, an
++     * underlying comparator specified in the constructor (or the default) is
++     * used to compare the non-<code>null</code> objects.
++     *
++     * @param o1 the first object to compare
++     * @param o2 the object to compare it to.
++     * @return <code>-1</code> if <code>o1</code> is "lower" than (less than,
++     *         before, etc.) <code>o2</code>; <code>1</code> if <code>o1</code> is
++     *         "higher" than (greater than, after, etc.) <code>o2</code>; or
++     *         <code>0</code> if <code>o1</code> and <code>o2</code> are equal.
++     */
++    public int compare(T o1, T o2) {
++        if (o1 == o2) {
++            return 0;
++        }
++        if (o1 == null) {
++            return (this.nullsAreHigh ? 1 : -1);
++        }
++        if (o2 == null) {
++            return (this.nullsAreHigh ? -1 : 1);
++        }
++        return this.nonNullComparator.compare(o1, o2);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Implement a hash code for this comparator that is consistent with
++     * {@link #equals(Object)}.
++     *
++     * @return a hash code for this comparator.
++     */
++    public int hashCode() {
++        return (nullsAreHigh ? -1 : 1) * nonNullComparator.hashCode();
++    }
++
++    /**
++     * Determines whether the specified object represents a comparator that is
++     * equal to this comparator.
++     *
++     * @param obj the object to compare this comparator with.
++     * @return <code>true</code> if the specified object is a NullComparator
++     *         with equivalent <code>null</code> comparison behavior
++     *         (i.e. <code>null</code> high or low) and with equivalent underlying
++     *         non-<code>null</code> object comparators.
++     */
++    public boolean equals(Object obj) {
++        if (obj == null) {
++            return false;
++        }
++        if (obj == this) {
++            return true;
++        }
++        if (!obj.getClass().equals(this.getClass())) {
++            return false;
++        }
++
++        NullComparator other = (NullComparator) obj;
++
++        return ((this.nullsAreHigh == other.nullsAreHigh) && (this.nonNullComparator.equals(other.nonNullComparator)));
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/comparators/ReverseComparator.java
+@@ -0,0 +1,109 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.comparators;
++
++import java.io.Serializable;
++import java.util.Comparator;
++
++/**
++ * Reverses the order of another comparator by reversing the arguments
++ * to its {@link #compare(Object, Object) compare} method.
++ *
++ * @author Henri Yandell
++ * @author Matt Hall, John Watkinson, Michael A. Smith
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @see java.util.Collections#reverseOrder()
++ * @since Commons Collections 2.0
++ */
++public class ReverseComparator <T> implements Comparator<T>, Serializable {
++
++    /**
++     * Serialization version from Collections 2.0.
++     */
++    private static final long serialVersionUID = 2858887242028539265L;
++
++    /**
++     * The comparator being decorated.
++     */
++    private Comparator<T> comparator;
++
++    /**
++     * Creates a comparator that inverts the comparison
++     * of the given comparator.  Pass in a {@link ComparableComparator}
++     * for reversing the natural order, as per
++     * {@link java.util.Collections#reverseOrder()}</b>.
++     *
++     * @param comparator Comparator to reverse
++     */
++    public ReverseComparator(Comparator<T> comparator) {
++        this.comparator = comparator;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Compares two objects in reverse order.
++     *
++     * @param obj1 the first object to compare
++     * @param obj2 the second object to compare
++     * @return negative if obj1 is less, positive if greater, zero if equal
++     */
++    public int compare(T obj1, T obj2) {
++        return comparator.compare(obj2, obj1);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Implement a hash code for this comparator that is consistent with
++     * {@link #equals(Object) equals}.
++     *
++     * @return a suitable hash code
++     * @since Commons Collections 3.0
++     */
++    public int hashCode() {
++        return "ReverseComparator".hashCode() ^ comparator.hashCode();
++    }
++
++    /**
++     * Returns <code>true</code> iff <i>that</i> Object is
++     * is a {@link Comparator} whose ordering is known to be
++     * equivalent to mine.
++     * <p/>
++     * This implementation returns <code>true</code>
++     * iff <code><i>object</i>.{@link Object#getClass() getClass()}</code>
++     * equals <code>this.getClass()</code>, and the underlying
++     * comparators are equal.
++     * Subclasses may want to override this behavior to remain consistent
++     * with the {@link Comparator#equals(Object) equals} contract.
++     *
++     * @param object the object to compare to
++     * @return true if equal
++     * @since Commons Collections 3.0
++     */
++    public boolean equals(Object object) {
++        if (this == object) {
++            return true;
++        } else if (null == object) {
++            return false;
++        } else if (object.getClass().equals(this.getClass())) {
++            ReverseComparator thatrc = (ReverseComparator) object;
++            return comparator.equals(thatrc.comparator);
++        } else {
++            return false;
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/comparators/TransformingComparator.java
+@@ -0,0 +1,70 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.comparators;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.util.Comparator;
++
++/**
++ * Decorates another Comparator with transformation behavior. That is, the
++ * return value from the transform operation will be passed to the decorated
++ * {@link Comparator#compare(Object,Object) compare} method.
++ *
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:20 $
++ * @see org.apache.commons.collections15.Transformer
++ * @see org.apache.commons.collections15.comparators.ComparableComparator
++ * @since Commons Collections 2.0 (?)
++ */
++public class TransformingComparator <I,O> implements Comparator<I> {
++
++    /**
++     * The decorated comparator.
++     */
++    protected Comparator<O> decorated;
++    /**
++     * The transformer being used.
++     */
++    protected Transformer<I, O> transformer;
++
++    /**
++     * Constructs an instance with the given Transformer and Comparator.
++     *
++     * @param transformer what will transform the arguments to <code>compare</code>
++     * @param decorated   the decorated Comparator
++     */
++    public TransformingComparator(Transformer<I, O> transformer, Comparator<O> decorated) {
++        this.decorated = decorated;
++        this.transformer = transformer;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns the result of comparing the values from the transform operation.
++     *
++     * @param obj1 the first object to transform then compare
++     * @param obj2 the second object to transform then compare
++     * @return negative if obj1 is less, positive if greater, zero if equal
++     */
++    public int compare(I obj1, I obj2) {
++        O value1 = this.transformer.transform(obj1);
++        O value2 = this.transformer.transform(obj2);
++        return this.decorated.compare(value1, value2);
++    }
++
++}
++
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/comparators/package.html
+@@ -0,0 +1,26 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:20 pents90 Exp $ -->
++ <!--
++   Copyright 2002-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<BODY>
++<p>
++This package contains implementations of the
++{@link java.util.Comparator Comparator} interface.
++<p>
++You may also consider using 
++{@link org.apache.commons.collections.ComparatorUtils ComparatorUtils},
++which is a single class that uses static methods to construct instances
++of the classes in this package.
++</BODY>
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/AllPredicate.java
+@@ -0,0 +1,108 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++import java.util.Collection;
++
++/**
++ * Predicate implementation that returns true if all the predicates return true.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class AllPredicate <T> implements Predicate<T>, PredicateDecorator<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -3094696765038308799L;
++
++    /**
++     * The array of predicates to call
++     */
++    private final Predicate<? super T>[] iPredicates;
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param predicates the predicates to check, cloned, not null
++     * @return the <code>all</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the array is null
++     */
++    public static <T> Predicate<T> getInstance(Predicate<? super T>[] predicates) {
++        FunctorUtils.validateMin2(predicates);
++        predicates = FunctorUtils.copy(predicates);
++        return new AllPredicate<T>(predicates);
++    }
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param predicates the predicates to check, cloned, not null
++     * @return the <code>all</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if any predicate in the array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     */
++    public static <T> Predicate<T> getInstance(Collection<Predicate<? super T>> predicates) {
++        Predicate[] preds = FunctorUtils.<T>validate(predicates);
++        return new AllPredicate<T>(preds);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicates the predicates to check, not cloned, not null
++     */
++    public AllPredicate(Predicate<? super T>[] predicates) {
++        super();
++        iPredicates = predicates;
++    }
++
++    /**
++     * Evaluates the predicate returning true if all predicates return true.
++     *
++     * @param object the input object
++     * @return true if all decorated predicates return true
++     */
++    public boolean evaluate(T object) {
++        for (int i = 0; i < iPredicates.length; i++) {
++            if (iPredicates[i].evaluate(object) == false) {
++                return false;
++            }
++        }
++        return true;
++    }
++
++    /**
++     * Gets the predicates, do not modify the array.
++     *
++     * @return the predicates
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T>[] getPredicates() {
++        return iPredicates;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/AndPredicate.java
+@@ -0,0 +1,94 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that returns true if both the predicates return true.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class AndPredicate <T> implements Predicate<T>, PredicateDecorator<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 4189014213763186912L;
++
++    /**
++     * The array of predicates to call
++     */
++    private final Predicate<? super T> iPredicate1;
++    /**
++     * The array of predicates to call
++     */
++    private final Predicate<? super T> iPredicate2;
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param predicate1 the first predicate to check, not null
++     * @param predicate2 the second predicate to check, not null
++     * @return the <code>and</code> predicate
++     * @throws IllegalArgumentException if either predicate is null
++     */
++    public static <T> Predicate<T> getInstance(Predicate<? super T> predicate1, Predicate<? super T> predicate2) {
++        if (predicate1 == null || predicate2 == null) {
++            throw new IllegalArgumentException("Predicate must not be null");
++        }
++        return new AndPredicate<T>(predicate1, predicate2);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicate1 the first predicate to check, not null
++     * @param predicate2 the second predicate to check, not null
++     */
++    public AndPredicate(Predicate<? super T> predicate1, Predicate<? super T> predicate2) {
++        super();
++        iPredicate1 = predicate1;
++        iPredicate2 = predicate2;
++    }
++
++    /**
++     * Evaluates the predicate returning true if both predicates return true.
++     *
++     * @param object the input object
++     * @return true if both decorated predicates return true
++     */
++    public boolean evaluate(T object) {
++        return (iPredicate1.evaluate(object) && iPredicate2.evaluate(object));
++    }
++
++    /**
++     * Gets the two predicates being decorated as an array.
++     *
++     * @return the predicates
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T>[] getPredicates() {
++        return new Predicate[]{iPredicate1, iPredicate2};
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/AnyPredicate.java
+@@ -0,0 +1,108 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++import java.util.Collection;
++
++/**
++ * Predicate implementation that returns true if any of the predicates return true.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class AnyPredicate <T> implements Predicate<T>, PredicateDecorator<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 7429999530934647542L;
++
++    /**
++     * The array of predicates to call
++     */
++    private final Predicate<? super T>[] iPredicates;
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param predicates the predicates to check, cloned, not null
++     * @return the <code>any</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the array is null
++     */
++    public static <T> Predicate<T> getInstance(Predicate<? super T>[] predicates) {
++        FunctorUtils.validateMin2(predicates);
++        predicates = FunctorUtils.copy(predicates);
++        return new AnyPredicate<T>(predicates);
++    }
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param predicates the predicates to check, cloned, not null
++     * @return the <code>all</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if any predicate in the array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     */
++    public static <T> Predicate<T> getInstance(Collection<Predicate<? super T>> predicates) {
++        Predicate[] preds = FunctorUtils.validate(predicates);
++        return new AnyPredicate<T>(preds);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicates the predicates to check, not cloned, not null
++     */
++    public AnyPredicate(Predicate<? super T>[] predicates) {
++        super();
++        iPredicates = predicates;
++    }
++
++    /**
++     * Evaluates the predicate returning true if any predicate returns true.
++     *
++     * @param object the input object
++     * @return true if any decorated predicate return true
++     */
++    public boolean evaluate(T object) {
++        for (int i = 0; i < iPredicates.length; i++) {
++            if (iPredicates[i].evaluate(object)) {
++                return true;
++            }
++        }
++        return false;
++    }
++
++    /**
++     * Gets the predicates, do not modify the array.
++     *
++     * @return the predicates
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T>[] getPredicates() {
++        return iPredicates;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/ChainedClosure.java
+@@ -0,0 +1,136 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Closure;
++
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Iterator;
++
++/**
++ * Closure implementation that chains the specified closures together.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class ChainedClosure <T> implements Closure<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -3520677225766901240L;
++
++    /**
++     * The closures to call in turn
++     */
++    private final Closure<? super T>[] iClosures;
++
++    /**
++     * Factory method that performs validation and copies the parameter array.
++     *
++     * @param closures the closures to chain, copied, no nulls
++     * @return the <code>chained</code> closure
++     * @throws IllegalArgumentException if the closures array is null
++     * @throws IllegalArgumentException if any closure in the array is null
++     */
++    public static <T> Closure<T> getInstance(Closure<? super T>[] closures) {
++        FunctorUtils.validate(closures);
++        if (closures.length == 0) {
++            return NOPClosure.INSTANCE;
++        }
++        closures = FunctorUtils.copy(closures);
++        return new ChainedClosure<T>(closures);
++    }
++
++    /**
++     * Create a new Closure that calls each closure in turn, passing the
++     * result into the next closure. The ordering is that of the iterator()
++     * method on the collection.
++     *
++     * @param closures a collection of closures to chain
++     * @return the <code>chained</code> closure
++     * @throws IllegalArgumentException if the closures collection is null
++     * @throws IllegalArgumentException if any closure in the collection is null
++     */
++    public static <T> Closure<T> getInstance(Collection<? super T> closures) {
++        if (closures == null) {
++            throw new IllegalArgumentException("Closure collection must not be null");
++        }
++        if (closures.size() == 0) {
++            return NOPClosure.INSTANCE;
++        }
++        // convert to array like this to guarantee iterator() ordering
++        Closure<? super T>[] cmds = new Closure[closures.size()];
++        int i = 0;
++        for (Iterator it = closures.iterator(); it.hasNext();) {
++            cmds[i++] = (Closure<? super T>) it.next();
++        }
++        FunctorUtils.validate(cmds);
++        return new ChainedClosure(cmds);
++    }
++
++    /**
++     * Factory method that performs validation.
++     *
++     * @param closure1 the first closure, not null
++     * @param closure2 the second closure, not null
++     * @return the <code>chained</code> closure
++     * @throws IllegalArgumentException if either closure is null
++     */
++    public static <T> Closure<T> getInstance(Closure<? super T> closure1, Closure<? super T> closure2) {
++        if (closure1 == null || closure2 == null) {
++            throw new IllegalArgumentException("Closures must not be null");
++        }
++        Closure<? super T>[] closures = new Closure[]{closure1, closure2};
++        return new ChainedClosure<T>(closures);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param closures the closures to chain, not copied, no nulls
++     */
++    public ChainedClosure(Closure<? super T>[] closures) {
++        super();
++        iClosures = closures;
++    }
++
++    /**
++     * Execute a list of closures.
++     *
++     * @param input the input object passed to each closure
++     */
++    public void execute(T input) {
++        for (int i = 0; i < iClosures.length; i++) {
++            iClosures[i].execute(input);
++        }
++    }
++
++    /**
++     * Gets the closures, do not modify the array.
++     *
++     * @return the closures
++     * @since Commons Collections 3.1
++     */
++    public Closure<? super T>[] getClosures() {
++        return iClosures;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/ChainedTransformer.java
+@@ -0,0 +1,142 @@
++// GenericsNote: Converted, but only partially type-safe.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Iterator;
++
++/**
++ * Transformer implementation that chains the specified transformers together.
++ * <p/>
++ * The input object is passed to the first transformer. The transformed result
++ * is passed to the second transformer and so on.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class ChainedTransformer <I,O> implements Transformer<I, O>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 3514945074733160196L;
++
++    /**
++     * The transformers to call in turn
++     */
++    private final Transformer[] iTransformers;
++
++    /**
++     * Factory method that performs validation and copies the parameter array.
++     *
++     * @param transformers the transformers to chain, copied, no nulls
++     * @return the <code>chained</code> transformer
++     * @throws IllegalArgumentException if the transformers array is null
++     * @throws IllegalArgumentException if any transformer in the array is null
++     */
++    public static <I,O> Transformer<I, O> getInstance(Transformer[] transformers) {
++        FunctorUtils.validate(transformers);
++        if (transformers.length == 0) {
++            return NOPTransformer.INSTANCE;
++        }
++        transformers = FunctorUtils.copy(transformers);
++        return new ChainedTransformer<I, O>(transformers);
++    }
++
++    /**
++     * Create a new Transformer that calls each transformer in turn, passing the
++     * result into the next transformer. The ordering is that of the iterator()
++     * method on the collection.
++     *
++     * @param transformers a collection of transformers to chain
++     * @return the <code>chained</code> transformer
++     * @throws IllegalArgumentException if the transformers collection is null
++     * @throws IllegalArgumentException if any transformer in the collection is null
++     */
++    public static <I,O> Transformer<I, O> getInstance(Collection<Transformer> transformers) {
++        if (transformers == null) {
++            throw new IllegalArgumentException("Transformer collection must not be null");
++        }
++        if (transformers.size() == 0) {
++            return NOPTransformer.INSTANCE;
++        }
++        // convert to array like this to guarantee iterator() ordering
++        Transformer[] cmds = new Transformer[transformers.size()];
++        int i = 0;
++        for (Iterator<Transformer> it = transformers.iterator(); it.hasNext();) {
++            cmds[i++] = it.next();
++        }
++        FunctorUtils.validate(cmds);
++        return new ChainedTransformer<I, O>(cmds);
++    }
++
++    /**
++     * Factory method that performs validation.
++     *
++     * @param transformer1 the first transformer, not null
++     * @param transformer2 the second transformer, not null
++     * @return the <code>chained</code> transformer
++     * @throws IllegalArgumentException if either transformer is null
++     */
++    public static <I,M,O> Transformer<I, O> getInstance(Transformer<I, ? extends M> transformer1, Transformer<? super M, O> transformer2) {
++        if (transformer1 == null || transformer2 == null) {
++            throw new IllegalArgumentException("Transformers must not be null");
++        }
++        Transformer[] transformers = new Transformer[]{transformer1, transformer2};
++        return new ChainedTransformer<I, O>(transformers);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param transformers the transformers to chain, not copied, no nulls
++     */
++    public ChainedTransformer(Transformer[] transformers) {
++        super();
++        iTransformers = transformers;
++    }
++
++    /**
++     * Transforms the input to result via each decorated transformer
++     *
++     * @param object the input object passed to the first transformer
++     * @return the transformed result
++     */
++    public O transform(I object) {
++        Object intermediate = object;
++        for (int i = 0; i < iTransformers.length; i++) {
++            intermediate = iTransformers[i].transform(intermediate);
++        }
++        return (O) intermediate;
++    }
++
++    /**
++     * Gets the transformers, do not modify the array.
++     *
++     * @return the transformers
++     * @since Commons Collections 3.1
++     */
++    public Transformer[] getTransformers() {
++        return iTransformers;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/CloneTransformer.java
+@@ -0,0 +1,74 @@
++// GenericsNote: Converted (nothing to convert).
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++
++/**
++ * Transformer implementation that returns a clone of the input object.
++ * <p/>
++ * Clone is performed using <code>PrototypeFactory.getInstance(input).create()</code>.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class CloneTransformer<T> implements Transformer<T,T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -8188742709499652567L;
++
++    /**
++     * Singleton predicate instance
++     */
++    public static final Transformer INSTANCE = new CloneTransformer();
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++	public static <T> Transformer<T,T> getInstance() {
++        return INSTANCE;
++    }
++
++    /**
++     * Constructor
++     */
++    private CloneTransformer() {
++        super();
++    }
++
++    /**
++     * Transforms the input to result by cloning it.
++     *
++     * @param input the input object to transform
++     * @return the transformed result
++     */
++    public T transform(T input) {
++        if (input == null) {
++            return null;
++        }
++        return PrototypeFactory.getInstance(input).create();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/ClosureTransformer.java
+@@ -0,0 +1,90 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Closure;
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++
++/**
++ * Transformer implementation that calls a Closure using the input object
++ * and then returns the input.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class ClosureTransformer <T> implements Transformer<T, T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 478466901448617286L;
++
++    /**
++     * The closure to wrap
++     */
++    private final Closure<T> iClosure;
++
++    /**
++     * Factory method that performs validation.
++     *
++     * @param closure the closure to call, not null
++     * @return the <code>closure</code> transformer
++     * @throws IllegalArgumentException if the closure is null
++     */
++    public static <T> Transformer<T, T> getInstance(Closure<T> closure) {
++        if (closure == null) {
++            throw new IllegalArgumentException("Closure must not be null");
++        }
++        return new ClosureTransformer<T>(closure);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param closure the closure to call, not null
++     */
++    public ClosureTransformer(Closure<T> closure) {
++        super();
++        iClosure = closure;
++    }
++
++    /**
++     * Transforms the input to result by executing a closure.
++     *
++     * @param input the input object to transform
++     * @return the transformed result
++     */
++    public T transform(T input) {
++        iClosure.execute(input);
++        return input;
++    }
++
++    /**
++     * Gets the closure.
++     *
++     * @return the closure
++     * @since Commons Collections 3.1
++     */
++    public Closure<T> getClosure() {
++        return iClosure;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/ConstantFactory.java
+@@ -0,0 +1,94 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Factory;
++
++import java.io.Serializable;
++
++/**
++ * Factory implementation that returns the same constant each time.
++ * <p/>
++ * No check is made that the object is immutable. In general, only immutable
++ * objects should use the constant factory. Mutable objects should
++ * use the prototype factory.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class ConstantFactory <T> implements Factory<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -3520677225766901240L;
++
++    /**
++     * Returns null each time
++     */
++    public static final Factory NULL_INSTANCE = new ConstantFactory(null);
++
++    /**
++     * The closures to call in turn
++     */
++    private final T iConstant;
++
++    /**
++     * Factory method that performs validation.
++     *
++     * @param constantToReturn the constant object to return each time in the factory
++     * @return the <code>constant</code> factory.
++     */
++    public static <T> Factory<T> getInstance(T constantToReturn) {
++        if (constantToReturn == null) {
++            return NULL_INSTANCE;
++        }
++        return new ConstantFactory<T>(constantToReturn);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param constantToReturn the constant to return each time
++     */
++    public ConstantFactory(T constantToReturn) {
++        super();
++        iConstant = constantToReturn;
++    }
++
++    /**
++     * Always return constant.
++     *
++     * @return the stored constant value
++     */
++    public T create() {
++        return iConstant;
++    }
++
++    /**
++     * Gets the constant.
++     *
++     * @return the constant
++     * @since Commons Collections 3.1
++     */
++    public T getConstant() {
++        return iConstant;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/ConstantTransformer.java
+@@ -0,0 +1,95 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++
++/**
++ * Transformer implementation that returns the same constant each time.
++ * <p/>
++ * No check is made that the object is immutable. In general, only immutable
++ * objects should use the constant factory. Mutable objects should
++ * use the prototype factory.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class ConstantTransformer <T> implements Transformer<Object, T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 6374440726369055124L;
++
++    /**
++     * Returns null each time
++     */
++    public static final Transformer NULL_INSTANCE = new ConstantTransformer(null);
++
++    /**
++     * The closures to call in turn
++     */
++    private final T iConstant;
++
++    /**
++     * Transformer method that performs validation.
++     *
++     * @param constantToReturn the constant object to return each time in the factory
++     * @return the <code>constant</code> factory.
++     */
++    public static <T> Transformer<Object, T> getInstance(T constantToReturn) {
++        if (constantToReturn == null) {
++            return NULL_INSTANCE;
++        }
++        return new ConstantTransformer<T>(constantToReturn);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param constantToReturn the constant to return each time
++     */
++    public ConstantTransformer(T constantToReturn) {
++        super();
++        iConstant = constantToReturn;
++    }
++
++    /**
++     * Transforms the input by ignoring it and returning the stored constant instead.
++     *
++     * @param input the input object which is ignored
++     * @return the stored constant
++     */
++    public T transform(Object input) {
++        return iConstant;
++    }
++
++    /**
++     * Gets the constant.
++     *
++     * @return the constant
++     * @since Commons Collections 3.1
++     */
++    public T getConstant() {
++        return iConstant;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/EqualPredicate.java
+@@ -0,0 +1,88 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that returns true if the input is the same object
++ * as the one stored in this predicate by equals.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class EqualPredicate <T> implements Predicate<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 5633766978029907089L;
++
++    /**
++     * The value to compare to
++     */
++    private final T iValue;
++
++    /**
++     * Factory to create the identity predicate.
++     *
++     * @param object the object to compare to
++     * @return the predicate
++     * @throws IllegalArgumentException if the predicate is null
++     */
++    public static <T> Predicate<T> getInstance(T object) {
++        if (object == null) {
++            return NullPredicate.INSTANCE;
++        }
++        return new EqualPredicate<T>(object);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param object the object to compare to
++     */
++    public EqualPredicate(T object) {
++        super();
++        iValue = object;
++    }
++
++    /**
++     * Evaluates the predicate returning true if the input equals the stored value.
++     *
++     * @param object the input object
++     * @return true if input object equals stored value
++     */
++    public boolean evaluate(T object) {
++        return (iValue.equals(object));
++    }
++
++    /**
++     * Gets the value.
++     *
++     * @return the value
++     * @since Commons Collections 3.1
++     */
++    public T getValue() {
++        return iValue;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/ExceptionClosure.java
+@@ -0,0 +1,71 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Closure;
++import org.apache.commons.collections15.FunctorException;
++
++import java.io.Serializable;
++
++/**
++ * Closure implementation that always throws an exception.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class ExceptionClosure <T> implements Closure<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 7179106032121985545L;
++
++
++    /**
++     * Singleton predicate instance
++     */
++    public static final Closure INSTANCE = new ExceptionClosure();
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++	public static <T> Closure<T> getInstance() {
++        return INSTANCE;
++    }
++
++    /**
++     * Restricted constructor.
++     */
++    private ExceptionClosure() {
++        super();
++    }
++
++    /**
++     * Always throw an exception.
++     *
++     * @param input the input object
++     * @throws FunctorException always
++     */
++    public void execute(T input) {
++        throw new FunctorException("ExceptionClosure invoked");
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/ExceptionFactory.java
+@@ -0,0 +1,71 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Factory;
++import org.apache.commons.collections15.FunctorException;
++
++import java.io.Serializable;
++
++/**
++ * Factory implementation that always throws an exception.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class ExceptionFactory <T> implements Factory<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 7179106032121985545L;
++
++
++    /**
++     * Singleton predicate instance
++     */
++    public static final Factory INSTANCE = new ExceptionFactory();
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++	public static <T> Factory<T> getInstance() {
++        return INSTANCE;
++    }
++
++    /**
++     * Restricted constructor.
++     */
++    private ExceptionFactory() {
++        super();
++    }
++
++    /**
++     * Always throws an exception.
++     *
++     * @return never
++     * @throws FunctorException always
++     */
++    public T create() {
++        throw new FunctorException("ExceptionFactory invoked");
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/ExceptionPredicate.java
+@@ -0,0 +1,71 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.FunctorException;
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that always throws an exception.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class ExceptionPredicate <T> implements Predicate<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 7179106032121985545L;
++
++    /**
++     * Singleton predicate instance
++     */
++    public static final Predicate INSTANCE = new ExceptionPredicate();
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++	public static <T> Predicate<T> getInstance() {
++        return INSTANCE;
++    }
++
++    /**
++     * Restricted constructor.
++     */
++    private ExceptionPredicate() {
++        super();
++    }
++
++    /**
++     * Evaluates the predicate always throwing an exception.
++     *
++     * @param object the input object
++     * @return never
++     * @throws FunctorException always
++     */
++    public boolean evaluate(T object) {
++        throw new FunctorException("ExceptionPredicate invoked");
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/ExceptionTransformer.java
+@@ -0,0 +1,72 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.FunctorException;
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++
++/**
++ * Transformer implementation that always throws an exception.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class ExceptionTransformer <I,O> implements Transformer<I, O>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 7179106032121985545L;
++
++
++    /**
++     * Singleton predicate instance
++     */
++    public static final Transformer INSTANCE = new ExceptionTransformer();
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++	public static <I,O> Transformer<I,O> getInstance() {
++        return INSTANCE;
++    }
++
++    /**
++     * Restricted constructor.
++     */
++    private ExceptionTransformer() {
++        super();
++    }
++
++    /**
++     * Transforms the input to result by cloning it.
++     *
++     * @param input the input object to transform
++     * @return never
++     * @throws FunctorException always
++     */
++    public O transform(I input) {
++        throw new FunctorException("ExceptionTransformer invoked");
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/FactoryTransformer.java
+@@ -0,0 +1,89 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Factory;
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++
++/**
++ * Transformer implementation that calls a Factory and returns the result.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class FactoryTransformer <I, T> implements Transformer<I, T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -6817674502475353160L;
++
++    /**
++     * The factory to wrap
++     */
++    private final Factory<T> iFactory;
++
++    /**
++     * Factory method that performs validation.
++     *
++     * @param factory the factory to call, not null
++     * @return the <code>factory</code> transformer
++     * @throws IllegalArgumentException if the factory is null
++     */
++    public static <K,T> Transformer<K, T> getInstance(Factory<T> factory) {
++        if (factory == null) {
++            throw new IllegalArgumentException("Factory must not be null");
++        }
++        return new FactoryTransformer<K, T>(factory);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param factory the factory to call, not null
++     */
++    public FactoryTransformer(Factory<T> factory) {
++        super();
++        iFactory = factory;
++    }
++
++    /**
++     * Transforms the input by ignoring the input and returning the result of
++     * calling the decorated factory.
++     *
++     * @param input the input object to transform
++     * @return the transformed result
++     */
++    public T transform(I input) {
++        return iFactory.create();
++    }
++
++    /**
++     * Gets the factory.
++     *
++     * @return the factory
++     * @since Commons Collections 3.1
++     */
++    public Factory<T> getFactory() {
++        return iFactory;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/FalsePredicate.java
+@@ -0,0 +1,69 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that always returns false.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class FalsePredicate <T> implements Predicate<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 7533784454832764388L;
++
++    /**
++     * Singleton predicate instance
++     */
++    public static final Predicate INSTANCE = new FalsePredicate();
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++    public static <T> Predicate<T> getInstance() {
++        return INSTANCE;
++    }
++
++    /**
++     * Restricted constructor.
++     */
++    private FalsePredicate() {
++        super();
++    }
++
++    /**
++     * Evaluates the predicate returning false always.
++     *
++     * @param object the input object
++     * @return false always
++     */
++    public boolean evaluate(T object) {
++        return false;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/ForClosure.java
+@@ -0,0 +1,110 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Closure;
++
++import java.io.Serializable;
++
++/**
++ * Closure implementation that calls another closure n times, like a for loop.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class ForClosure <T> implements Closure<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -1190120533393621674L;
++
++    /**
++     * The number of times to loop
++     */
++    private final int iCount;
++    /**
++     * The closure to call
++     */
++    private final Closure<T> iClosure;
++
++    /**
++     * Factory method that performs validation.
++     * <p/>
++     * A null closure or zero count returns the <code>NOPClosure</code>.
++     * A count of one returns the specified closure.
++     *
++     * @param count   the number of times to execute the closure
++     * @param closure the closure to execute, not null
++     * @return the <code>for</code> closure
++     */
++    public static <T> Closure<T> getInstance(int count, Closure<T> closure) {
++        if (count <= 0 || closure == null) {
++            return NOPClosure.INSTANCE;
++        }
++        if (count == 1) {
++            return closure;
++        }
++        return new ForClosure<T>(count, closure);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param count   the number of times to execute the closure
++     * @param closure the closure to execute, not null
++     */
++    public ForClosure(int count, Closure<T> closure) {
++        super();
++        iCount = count;
++        iClosure = closure;
++    }
++
++    /**
++     * Executes the closure <code>count</code> times.
++     *
++     * @param input the input object
++     */
++    public void execute(T input) {
++        for (int i = 0; i < iCount; i++) {
++            iClosure.execute(input);
++        }
++    }
++
++    /**
++     * Gets the closure.
++     *
++     * @return the closure
++     * @since Commons Collections 3.1
++     */
++    public Closure<T> getClosure() {
++        return iClosure;
++    }
++
++    /**
++     * Gets the count.
++     *
++     * @return the count
++     * @since Commons Collections 3.1
++     */
++    public int getCount() {
++        return iCount;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/FunctorUtils.java
+@@ -0,0 +1,174 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Closure;
++import org.apache.commons.collections15.Predicate;
++import org.apache.commons.collections15.Transformer;
++
++import java.util.Collection;
++import java.util.Iterator;
++
++/**
++ * Internal utilities for functors.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++class FunctorUtils {
++
++    /**
++     * Restricted constructor.
++     */
++    private FunctorUtils() {
++        super();
++    }
++
++    /**
++     * Clone the predicates to ensure that the internal reference can't be messed with.
++     *
++     * @param predicates the predicates to copy
++     * @return the cloned predicates
++     */
++    static <T> Predicate<? super T>[] copy(Predicate<? super T>[] predicates) {
++        if (predicates == null) {
++            return null;
++        }
++        return (Predicate<? super T>[]) predicates.clone();
++    }
++
++    /**
++     * Validate the predicates to ensure that all is well.
++     *
++     * @param predicates the predicates to validate
++     */
++    static <T> void validate(Predicate<? super T>[] predicates) {
++        if (predicates == null) {
++            throw new IllegalArgumentException("The predicate array must not be null");
++        }
++        for (int i = 0; i < predicates.length; i++) {
++            if (predicates[i] == null) {
++                throw new IllegalArgumentException("The predicate array must not contain a null predicate, index " + i + " was null");
++            }
++        }
++    }
++
++    /**
++     * Validate the predicates to ensure that all is well.
++     *
++     * @param predicates the predicates to validate
++     */
++    static <T> void validateMin2(Predicate<? super T>[] predicates) {
++        if (predicates == null) {
++            throw new IllegalArgumentException("The predicate array must not be null");
++        }
++        if (predicates.length < 2) {
++            throw new IllegalArgumentException("At least 2 predicates must be specified in the predicate array, size was " + predicates.length);
++        }
++        for (int i = 0; i < predicates.length; i++) {
++            if (predicates[i] == null) {
++                throw new IllegalArgumentException("The predicate array must not contain a null predicate, index " + i + " was null");
++            }
++        }
++    }
++
++    /**
++     * Validate the predicates to ensure that all is well.
++     *
++     * @param predicates the predicates to validate
++     * @return predicate array
++     */
++    static <T> Predicate<? super T>[] validate(Collection<Predicate<? super T>> predicates) {
++        if (predicates == null) {
++            throw new IllegalArgumentException("The predicate collection must not be null");
++        }
++        if (predicates.size() < 2) {
++            throw new IllegalArgumentException("At least 2 predicates must be specified in the predicate collection, size was " + predicates.size());
++        }
++        // convert to array like this to guarantee iterator() ordering
++        Predicate<? super T>[] preds = new Predicate[predicates.size()];
++        int i = 0;
++        for (Iterator<Predicate<? super T>> it = predicates.iterator(); it.hasNext();) {
++            preds[i] = it.next();
++            if (preds[i] == null) {
++                throw new IllegalArgumentException("The predicate collection must not contain a null predicate, index " + i + " was null");
++            }
++            i++;
++        }
++        return preds;
++    }
++
++    /**
++     * Clone the closures to ensure that the internal reference can't be messed with.
++     *
++     * @param closures the closures to copy
++     * @return the cloned closures
++     */
++    static <T> Closure<? super T>[] copy(Closure<? super T>[] closures) {
++        if (closures == null) {
++            return null;
++        }
++        return (Closure<? super T>[]) closures.clone();
++    }
++
++    /**
++     * Validate the closures to ensure that all is well.
++     *
++     * @param closures the closures to validate
++     */
++    static <T> void validate(Closure<? super T>[] closures) {
++        if (closures == null) {
++            throw new IllegalArgumentException("The closure array must not be null");
++        }
++        for (int i = 0; i < closures.length; i++) {
++            if (closures[i] == null) {
++                throw new IllegalArgumentException("The closure array must not contain a null closure, index " + i + " was null");
++            }
++        }
++    }
++
++    /**
++     * Copy method
++     *
++     * @param transformers the transformers to copy
++     * @return a clone of the transformers
++     */
++    static <I,O> Transformer<? super I, ? extends O>[] copy(Transformer<? super I, ? extends O>[] transformers) {
++        if (transformers == null) {
++            return null;
++        }
++        return (Transformer<? super I, ? extends O>[]) transformers.clone();
++    }
++
++    /**
++     * Validate method
++     *
++     * @param transformers the transformers to validate
++     */
++    static <I,O> void validate(Transformer<? super I, ? extends O>[] transformers) {
++        if (transformers == null) {
++            throw new IllegalArgumentException("The transformer array must not be null");
++        }
++        for (int i = 0; i < transformers.length; i++) {
++            if (transformers[i] == null) {
++                throw new IllegalArgumentException("The transformer array must not contain a null transformer, index " + i + " was null");
++            }
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/IdentityPredicate.java
+@@ -0,0 +1,90 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that returns true if the input is the same object
++ * as the one stored in this predicate.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class IdentityPredicate <T> implements Predicate<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -89901658494523293L;
++
++
++    /**
++     * The value to compare to
++     */
++    private final T iValue;
++
++    /**
++     * Factory to create the identity predicate.
++     *
++     * @param object the object to compare to
++     * @return the predicate
++     * @throws IllegalArgumentException if the predicate is null
++     */
++    public static <T> Predicate<T> getInstance(T object) {
++        if (object == null) {
++            return NullPredicate.INSTANCE;
++        }
++        return new IdentityPredicate<T>(object);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param object the object to compare to
++     */
++    public IdentityPredicate(T object) {
++        super();
++        iValue = object;
++    }
++
++    /**
++     * Evaluates the predicate returning true if the input object is identical to
++     * the stored object.
++     *
++     * @param object the input object
++     * @return true if input is the same object as the stored value
++     */
++    public boolean evaluate(T object) {
++        return (iValue == object);
++    }
++
++    /**
++     * Gets the value.
++     *
++     * @return the value
++     * @since Commons Collections 3.1
++     */
++    public T getValue() {
++        return iValue;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/IfClosure.java
+@@ -0,0 +1,129 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Closure;
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Closure implementation acts as an if statement calling one or other closure
++ * based on a predicate.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class IfClosure <T> implements Closure<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 3518477308466486130L;
++
++    /**
++     * The test
++     */
++    private final Predicate<? super T> iPredicate;
++    /**
++     * The closure to use if true
++     */
++    private final Closure<? super T> iTrueClosure;
++    /**
++     * The closure to use if false
++     */
++    private final Closure<? super T> iFalseClosure;
++
++    /**
++     * Factory method that performs validation.
++     *
++     * @param predicate    predicate to switch on
++     * @param trueClosure  closure used if true
++     * @param falseClosure closure used if false
++     * @return the <code>if</code> closure
++     * @throws IllegalArgumentException if any argument is null
++     */
++    public static <T> Closure<T> getInstance(Predicate<? super T> predicate, Closure<? super T> trueClosure, Closure<? super T> falseClosure) {
++        if (predicate == null) {
++            throw new IllegalArgumentException("Predicate must not be null");
++        }
++        if (trueClosure == null || falseClosure == null) {
++            throw new IllegalArgumentException("Closures must not be null");
++        }
++        return new IfClosure<T>(predicate, trueClosure, falseClosure);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicate    predicate to switch on, not null
++     * @param trueClosure  closure used if true, not null
++     * @param falseClosure closure used if false, not null
++     */
++    public IfClosure(Predicate<? super T> predicate, Closure<? super T> trueClosure, Closure<? super T> falseClosure) {
++        super();
++        iPredicate = predicate;
++        iTrueClosure = trueClosure;
++        iFalseClosure = falseClosure;
++    }
++
++    /**
++     * Executes the true or false closure accoring to the result of the predicate.
++     *
++     * @param input the input object
++     */
++    public void execute(T input) {
++        if (iPredicate.evaluate(input) == true) {
++            iTrueClosure.execute(input);
++        } else {
++            iFalseClosure.execute(input);
++        }
++    }
++
++    /**
++     * Gets the predicate.
++     *
++     * @return the predicate
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T> getPredicate() {
++        return iPredicate;
++    }
++
++    /**
++     * Gets the closure called when true.
++     *
++     * @return the closure
++     * @since Commons Collections 3.1
++     */
++    public Closure<? super T> getTrueClosure() {
++        return iTrueClosure;
++    }
++
++    /**
++     * Gets the closure called when false.
++     *
++     * @return the closure
++     * @since Commons Collections 3.1
++     */
++    public Closure<? super T> getFalseClosure() {
++        return iFalseClosure;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/InstanceofPredicate.java
+@@ -0,0 +1,90 @@
++// GenericsNote: Converted, although perhaps this should not be templated. Not sure!
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that returns true if the input is an instanceof
++ * the type stored in this predicate.
++ *
++ * Since this predicate operates on the type of the objects passed to it, generics are not used.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class InstanceofPredicate implements Predicate, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -6682656911025165584L;
++
++    /**
++     * The type to compare to
++     */
++    private final Class iType;
++
++    /**
++     * Factory to create the identity predicate.
++     *
++     * @param type the type to check for, may not be null
++     * @return the predicate
++     * @throws IllegalArgumentException if the class is null
++     */
++    public static Predicate getInstance(Class type) {
++        if (type == null) {
++            throw new IllegalArgumentException("The type to check instanceof must not be null");
++        }
++        return new InstanceofPredicate(type);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param type the type to check for
++     */
++    public InstanceofPredicate(Class type) {
++        super();
++        iType = type;
++    }
++
++    /**
++     * Evaluates the predicate returning true if the input object is of the correct type.
++     *
++     * @param object the input object
++     * @return true if input is of stored type
++     */
++    public boolean evaluate(Object object) {
++        return (iType.isInstance(object));
++    }
++
++    /**
++     * Gets the type to compare to.
++     *
++     * @return the type
++     * @since Commons Collections 3.1
++     */
++    public Class getType() {
++        return iType;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/InstantiateFactory.java
+@@ -0,0 +1,147 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Factory;
++import org.apache.commons.collections15.FunctorException;
++
++import java.io.Serializable;
++import java.lang.reflect.Constructor;
++import java.lang.reflect.InvocationTargetException;
++
++/**
++ * Factory implementation that creates a new object instance by reflection.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class InstantiateFactory <T> implements Factory<T>, Serializable {
++
++    /**
++     * The serial version
++     */
++    static final long serialVersionUID = -7732226881069447957L;
++
++    /**
++     * The class to create
++     */
++    private final Class<T> iClassToInstantiate;
++    /**
++     * The constructor parameter types
++     */
++    private final Class[] iParamTypes;
++    /**
++     * The constructor arguments
++     */
++    private final Object[] iArgs;
++    /**
++     * The constructor
++     */
++    private transient Constructor iConstructor = null;
++
++    /**
++     * Factory method that performs validation.
++     *
++     * @param classToInstantiate the class to instantiate, not null
++     * @param paramTypes         the constructor parameter types
++     * @param args               the constructor arguments
++     * @return a new instantiate factory
++     */
++    public static <T> Factory<T> getInstance(Class<T> classToInstantiate, Class[] paramTypes, Object[] args) {
++        if (classToInstantiate == null) {
++            throw new IllegalArgumentException("Class to instantiate must not be null");
++        }
++        if (((paramTypes == null) && (args != null)) || ((paramTypes != null) && (args == null)) || ((paramTypes != null) && (args != null) && (paramTypes.length != args.length))) {
++            throw new IllegalArgumentException("Parameter types must match the arguments");
++        }
++
++        if (paramTypes == null || paramTypes.length == 0) {
++            return new InstantiateFactory<T>(classToInstantiate);
++        } else {
++            paramTypes = (Class[]) paramTypes.clone();
++            args = (Object[]) args.clone();
++            return new InstantiateFactory<T>(classToInstantiate, paramTypes, args);
++        }
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param classToInstantiate the class to instantiate
++     */
++    public InstantiateFactory(Class<T> classToInstantiate) {
++        super();
++        iClassToInstantiate = classToInstantiate;
++        iParamTypes = null;
++        iArgs = null;
++        findConstructor();
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param classToInstantiate the class to instantiate
++     * @param paramTypes         the constructor parameter types, not cloned
++     * @param args               the constructor arguments, not cloned
++     */
++    public InstantiateFactory(Class<T> classToInstantiate, Class[] paramTypes, Object[] args) {
++        super();
++        iClassToInstantiate = classToInstantiate;
++        iParamTypes = paramTypes;
++        iArgs = args;
++        findConstructor();
++    }
++
++    /**
++     * Find the Constructor for the class specified.
++     */
++    private void findConstructor() {
++        try {
++            iConstructor = iClassToInstantiate.getConstructor(iParamTypes);
++
++        } catch (NoSuchMethodException ex) {
++            throw new IllegalArgumentException("InstantiateFactory: The constructor must exist and be public ");
++        }
++    }
++
++    /**
++     * Creates an object using the stored constructor.
++     *
++     * @return the new object
++     */
++    public T create() {
++        // needed for post-serialization
++        if (iConstructor == null) {
++            findConstructor();
++        }
++
++        try {
++            return (T) iConstructor.newInstance(iArgs);
++
++        } catch (InstantiationException ex) {
++            throw new FunctorException("InstantiateFactory: InstantiationException", ex);
++        } catch (IllegalAccessException ex) {
++            throw new FunctorException("InstantiateFactory: Constructor must be public", ex);
++        } catch (InvocationTargetException ex) {
++            throw new FunctorException("InstantiateFactory: Constructor threw an exception", ex);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/InstantiateTransformer.java
+@@ -0,0 +1,119 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.FunctorException;
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++import java.lang.reflect.Constructor;
++import java.lang.reflect.InvocationTargetException;
++
++/**
++ * Transformer implementation that creates a new object instance by reflection.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class InstantiateTransformer implements Transformer<Class, Object>, Serializable {
++
++    /**
++     * The serial version
++     */
++    static final long serialVersionUID = 3786388740793356347L;
++
++    /**
++     * Singleton instance that uses the no arg constructor
++     */
++    public static final InstantiateTransformer NO_ARG_INSTANCE = new InstantiateTransformer();
++
++    /**
++     * The constructor parameter types
++     */
++    private final Class[] iParamTypes;
++    /**
++     * The constructor arguments
++     */
++    private final Object[] iArgs;
++
++    /**
++     * Transformer method that performs validation.
++     *
++     * @param paramTypes the constructor parameter types
++     * @param args       the constructor arguments
++     * @return an instantiate transformer
++     */
++    public static InstantiateTransformer getInstance(Class[] paramTypes, Object[] args) {
++        if (((paramTypes == null) && (args != null)) || ((paramTypes != null) && (args == null)) || ((paramTypes != null) && (args != null) && (paramTypes.length != args.length))) {
++            throw new IllegalArgumentException("Parameter types must match the arguments");
++        }
++
++        if (paramTypes == null || paramTypes.length == 0) {
++            return NO_ARG_INSTANCE;
++        } else {
++            paramTypes = (Class[]) paramTypes.clone();
++            args = (Object[]) args.clone();
++        }
++        return new InstantiateTransformer(paramTypes, args);
++    }
++
++    /**
++     * Constructor for no arg instance.
++     */
++    private InstantiateTransformer() {
++        super();
++        iParamTypes = null;
++        iArgs = null;
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param paramTypes the constructor parameter types, not cloned
++     * @param args       the constructor arguments, not cloned
++     */
++    public InstantiateTransformer(Class[] paramTypes, Object[] args) {
++        super();
++        iParamTypes = paramTypes;
++        iArgs = args;
++    }
++
++    /**
++     * Transforms the input Class object to a result by instantiation.
++     *
++     * @param input the input object to transform
++     * @return the transformed result
++     */
++    public Object transform(Class input) {
++        try {
++            Constructor con = ((Class) input).getConstructor(iParamTypes);
++            return con.newInstance(iArgs);
++
++        } catch (NoSuchMethodException ex) {
++            throw new FunctorException("InstantiateTransformer: The constructor must exist and be public ");
++        } catch (InstantiationException ex) {
++            throw new FunctorException("InstantiateTransformer: InstantiationException", ex);
++        } catch (IllegalAccessException ex) {
++            throw new FunctorException("InstantiateTransformer: Constructor must be public", ex);
++        } catch (InvocationTargetException ex) {
++            throw new FunctorException("InstantiateTransformer: Constructor threw an exception", ex);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/InvokerTransformer.java
+@@ -0,0 +1,142 @@
++// GenericsNote: Converted (nothing to convert).
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.FunctorException;
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++import java.lang.reflect.InvocationTargetException;
++import java.lang.reflect.Method;
++
++/**
++ * Transformer implementation that creates a new object instance by reflection.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class InvokerTransformer implements Transformer, Serializable {
++
++    /**
++     * The serial version
++     */
++    static final long serialVersionUID = -8653385846894047688L;
++
++    /**
++     * The method name to call
++     */
++    private final String iMethodName;
++    /**
++     * The array of reflection parameter types
++     */
++    private final Class[] iParamTypes;
++    /**
++     * The array of reflection arguments
++     */
++    private final Object[] iArgs;
++
++    /**
++     * Gets an instance of this transformer calling a specific method with no arguments.
++     *
++     * @param methodName the method name to call
++     * @return an invoker transformer
++     * @since Commons Collections 3.1
++     */
++    public static Transformer getInstance(String methodName) {
++        if (methodName == null) {
++            throw new IllegalArgumentException("The method to invoke must not be null");
++        }
++        return new InvokerTransformer(methodName);
++    }
++
++    /**
++     * Gets an instance of this transformer calling a specific method with specific values.
++     *
++     * @param methodName the method name to call
++     * @param paramTypes the parameter types of the method
++     * @param args       the arguments to pass to the method
++     * @return an invoker transformer
++     */
++    public static Transformer getInstance(String methodName, Class[] paramTypes, Object[] args) {
++        if (methodName == null) {
++            throw new IllegalArgumentException("The method to invoke must not be null");
++        }
++        if (((paramTypes == null) && (args != null)) || ((paramTypes != null) && (args == null)) || ((paramTypes != null) && (args != null) && (paramTypes.length != args.length))) {
++            throw new IllegalArgumentException("The parameter types must match the arguments");
++        }
++        if (paramTypes == null || paramTypes.length == 0) {
++            return new InvokerTransformer(methodName);
++        } else {
++            paramTypes = (Class[]) paramTypes.clone();
++            args = (Object[]) args.clone();
++            return new InvokerTransformer(methodName, paramTypes, args);
++        }
++    }
++
++    /**
++     * Constructor for no arg instance.
++     *
++     * @param methodName the method to call
++     */
++    private InvokerTransformer(String methodName) {
++        super();
++        iMethodName = methodName;
++        iParamTypes = null;
++        iArgs = null;
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param methodName the method to call
++     * @param paramTypes the constructor parameter types, not cloned
++     * @param args       the constructor arguments, not cloned
++     */
++    public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
++        super();
++        iMethodName = methodName;
++        iParamTypes = paramTypes;
++        iArgs = args;
++    }
++
++    /**
++     * Transforms the input to result by invoking a method on the input.
++     *
++     * @param input the input object to transform
++     * @return the transformed result, null if null input
++     */
++    public Object transform(Object input) {
++        if (input == null) {
++            return null;
++        }
++        try {
++            Class cls = input.getClass();
++            Method method = cls.getMethod(iMethodName, iParamTypes);
++            return method.invoke(input, iArgs);
++
++        } catch (NoSuchMethodException ex) {
++            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");
++        } catch (IllegalAccessException ex) {
++            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
++        } catch (InvocationTargetException ex) {
++            throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/MapTransformer.java
+@@ -0,0 +1,90 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++import java.util.Map;
++
++/**
++ * Transformer implementation that returns the value held in a specified map
++ * using the input parameter as a key.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class MapTransformer <I,O> implements Transformer<I, O>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 862391807045468939L;
++
++    /**
++     * The map of data to lookup in
++     */
++    private final Map<I, O> iMap;
++
++    /**
++     * Factory to create the transformer.
++     * <p/>
++     * If the map is null, a transformer that always returns null is returned.
++     *
++     * @param map the map, not cloned
++     * @return the transformer
++     */
++    public static <I,O> Transformer<I, O> getInstance(Map<I, O> map) {
++        if (map == null) {
++            return ConstantTransformer.NULL_INSTANCE;
++        }
++        return new MapTransformer<I, O>(map);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param map the map to use for lookup, not cloned
++     */
++    private MapTransformer(Map<I, O> map) {
++        super();
++        iMap = map;
++    }
++
++    /**
++     * Transforms the input to result by looking it up in a <code>Map</code>.
++     *
++     * @param input the input object to transform
++     * @return the transformed result
++     */
++    public O transform(I input) {
++        return iMap.get(input);
++    }
++
++    /**
++     * Gets the map to lookup in.
++     *
++     * @return the map
++     * @since Commons Collections 3.1
++     */
++    public Map<I, O> getMap() {
++        return iMap;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/NOPClosure.java
+@@ -0,0 +1,68 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Closure;
++
++import java.io.Serializable;
++
++/**
++ * Closure implementation that does nothing.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class NOPClosure <T> implements Closure<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 3518477308466486130L;
++
++    /**
++     * Singleton predicate instance
++     */
++    public static final Closure INSTANCE = new NOPClosure();
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++	public static <T> Closure<T> getInstance() {
++        return INSTANCE;
++    }
++
++    /**
++     * Constructor
++     */
++    private NOPClosure() {
++        super();
++    }
++
++    /**
++     * Do nothing.
++     *
++     * @param input the input object
++     */
++    public void execute(T input) {
++        // do nothing
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/NOPTransformer.java
+@@ -0,0 +1,69 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++
++/**
++ * Transformer implementation that does nothing.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class NOPTransformer <I> implements Transformer<I, I>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 2133891748318574490L;
++
++    /**
++     * Singleton predicate instance
++     */
++    public static final Transformer INSTANCE = new NOPTransformer();
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++	public static <T> Transformer<T,T> getInstance() {
++        return INSTANCE;
++    }
++
++    /**
++     * Constructor
++     */
++    private NOPTransformer() {
++        super();
++    }
++
++    /**
++     * Transforms the input to result by doing nothing.
++     *
++     * @param input the input object to transform
++     * @return the transformed result which is the input
++     */
++    public I transform(I input) {
++        return input;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/NonePredicate.java
+@@ -0,0 +1,108 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++import java.util.Collection;
++
++/**
++ * Predicate implementation that returns true if none of the predicates return true.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class NonePredicate <T> implements Predicate<T>, PredicateDecorator<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 2007613066565892961L;
++
++    /**
++     * The array of predicates to call
++     */
++    private final Predicate<? super T>[] iPredicates;
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param predicates the predicates to check, cloned, not null
++     * @return the <code>any</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the array is null
++     */
++    public static <T> Predicate<T> getInstance(Predicate<? super T>[] predicates) {
++        FunctorUtils.validateMin2(predicates);
++        predicates = FunctorUtils.copy(predicates);
++        return new NonePredicate<T>(predicates);
++    }
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param predicates the predicates to check, cloned, not null
++     * @return the <code>one</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if any predicate in the array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     */
++    public static <T> Predicate<T> getInstance(Collection<Predicate<? super T>> predicates) {
++        Predicate[] preds = FunctorUtils.validate(predicates);
++        return new NonePredicate<T>(preds);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicates the predicates to check, not cloned, not null
++     */
++    public NonePredicate(Predicate[] predicates) {
++        super();
++        iPredicates = predicates;
++    }
++
++    /**
++     * Evaluates the predicate returning false if any stored predicate returns false.
++     *
++     * @param object the input object
++     * @return true if none of decorated predicates return true
++     */
++    public boolean evaluate(T object) {
++        for (int i = 0; i < iPredicates.length; i++) {
++            if (iPredicates[i].evaluate(object)) {
++                return false;
++            }
++        }
++        return true;
++    }
++
++    /**
++     * Gets the predicates, do not modify the array.
++     *
++     * @return the predicates
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T>[] getPredicates() {
++        return iPredicates;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/NotNullPredicate.java
+@@ -0,0 +1,69 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that returns true if the input is not null.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class NotNullPredicate <T> implements Predicate<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 7533784454832764388L;
++
++    /**
++     * Singleton predicate instance
++     */
++    public static final Predicate INSTANCE = new NotNullPredicate();
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++    public static <T> Predicate<T> getInstance() {
++        return INSTANCE;
++    }
++
++    /**
++     * Restricted constructor.
++     */
++    private NotNullPredicate() {
++        super();
++    }
++
++    /**
++     * Evaluates the predicate returning true if the object does not equal null.
++     *
++     * @param object the object to evaluate
++     * @return true if not null
++     */
++    public boolean evaluate(T object) {
++        return (object != null);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/NotPredicate.java
+@@ -0,0 +1,87 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that returns the opposite of the decorated predicate.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class NotPredicate <T> implements Predicate<T>, PredicateDecorator<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -2654603322338049674L;
++
++    /**
++     * The predicate to decorate
++     */
++    private final Predicate<T> iPredicate;
++
++    /**
++     * Factory to create the not predicate.
++     *
++     * @param predicate the predicate to decorate, not null
++     * @return the predicate
++     * @throws IllegalArgumentException if the predicate is null
++     */
++    public static <T> Predicate<T> getInstance(Predicate<T> predicate) {
++        if (predicate == null) {
++            throw new IllegalArgumentException("Predicate must not be null");
++        }
++        return new NotPredicate<T>(predicate);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicate the predicate to call after the null check
++     */
++    public NotPredicate(Predicate<T> predicate) {
++        super();
++        iPredicate = predicate;
++    }
++
++    /**
++     * Evaluates the predicate returning the opposite to the stored predicate.
++     *
++     * @param object the input object
++     * @return true if predicate returns false
++     */
++    public boolean evaluate(T object) {
++        return !(iPredicate.evaluate(object));
++    }
++
++    /**
++     * Gets the predicate being decorated.
++     *
++     * @return the predicate as the only element in an array
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T>[] getPredicates() {
++        return new Predicate[]{iPredicate};
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/NullIsExceptionPredicate.java
+@@ -0,0 +1,93 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.FunctorException;
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that throws an exception if the input is null.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class NullIsExceptionPredicate <T> implements Predicate<T>, PredicateDecorator<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 3243449850504576071L;
++
++    /**
++     * The predicate to decorate
++     */
++    private final Predicate<T> iPredicate;
++
++    /**
++     * Factory to create the null exception predicate.
++     *
++     * @param predicate the predicate to decorate, not null
++     * @return the predicate
++     * @throws IllegalArgumentException if the predicate is null
++     */
++    public static <T> Predicate<T> getInstance(Predicate<T> predicate) {
++        if (predicate == null) {
++            throw new IllegalArgumentException("Predicate must not be null");
++        }
++        return new NullIsExceptionPredicate<T>(predicate);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicate the predicate to call after the null check
++     */
++    public NullIsExceptionPredicate(Predicate<T> predicate) {
++        super();
++        iPredicate = predicate;
++    }
++
++    /**
++     * Evaluates the predicate returning the result of the decorated predicate
++     * once a null check is performed.
++     *
++     * @param object the input object
++     * @return true if decorated predicate returns true
++     * @throws FunctorException if input is null
++     */
++    public boolean evaluate(T object) {
++        if (object == null) {
++            throw new FunctorException("Input Object must not be null");
++        }
++        return iPredicate.evaluate(object);
++    }
++
++    /**
++     * Gets the predicate being decorated.
++     *
++     * @return the predicate as the only element in an array
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T>[] getPredicates() {
++        return new Predicate[]{iPredicate};
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/NullIsFalsePredicate.java
+@@ -0,0 +1,91 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that returns false if the input is null.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class NullIsFalsePredicate <T> implements Predicate<T>, PredicateDecorator<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -2997501534564735525L;
++
++    /**
++     * The predicate to decorate
++     */
++    private final Predicate<T> iPredicate;
++
++    /**
++     * Factory to create the null false predicate.
++     *
++     * @param predicate the predicate to decorate, not null
++     * @return the predicate
++     * @throws IllegalArgumentException if the predicate is null
++     */
++    public static <T> Predicate<T> getInstance(Predicate<T> predicate) {
++        if (predicate == null) {
++            throw new IllegalArgumentException("Predicate must not be null");
++        }
++        return new NullIsFalsePredicate<T>(predicate);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicate the predicate to call after the null check
++     */
++    public NullIsFalsePredicate(Predicate<T> predicate) {
++        super();
++        iPredicate = predicate;
++    }
++
++    /**
++     * Evaluates the predicate returning the result of the decorated predicate
++     * once a null check is performed.
++     *
++     * @param object the input object
++     * @return true if decorated predicate returns true, false if input is null
++     */
++    public boolean evaluate(T object) {
++        if (object == null) {
++            return false;
++        }
++        return iPredicate.evaluate(object);
++    }
++
++    /**
++     * Gets the predicate being decorated.
++     *
++     * @return the predicate as the only element in an array
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T>[] getPredicates() {
++        return new Predicate[]{iPredicate};
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/NullIsTruePredicate.java
+@@ -0,0 +1,91 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that returns true if the input is null.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class NullIsTruePredicate <T> implements Predicate<T>, PredicateDecorator<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -7625133768987126273L;
++
++    /**
++     * The predicate to decorate
++     */
++    private final Predicate<T> iPredicate;
++
++    /**
++     * Factory to create the null true predicate.
++     *
++     * @param predicate the predicate to decorate, not null
++     * @return the predicate
++     * @throws IllegalArgumentException if the predicate is null
++     */
++    public static <T> Predicate<T> getInstance(Predicate<T> predicate) {
++        if (predicate == null) {
++            throw new IllegalArgumentException("Predicate must not be null");
++        }
++        return new NullIsTruePredicate<T>(predicate);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicate the predicate to call after the null check
++     */
++    public NullIsTruePredicate(Predicate<T> predicate) {
++        super();
++        iPredicate = predicate;
++    }
++
++    /**
++     * Evaluates the predicate returning the result of the decorated predicate
++     * once a null check is performed.
++     *
++     * @param object the input object
++     * @return true if decorated predicate returns true or input is null
++     */
++    public boolean evaluate(T object) {
++        if (object == null) {
++            return true;
++        }
++        return iPredicate.evaluate(object);
++    }
++
++    /**
++     * Gets the predicate being decorated.
++     *
++     * @return the predicate as the only element in an array
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T>[] getPredicates() {
++        return new Predicate[]{iPredicate};
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/NullPredicate.java
+@@ -0,0 +1,69 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that returns true if the input is null.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class NullPredicate <T> implements Predicate<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 7533784454832764388L;
++
++    /**
++     * Singleton predicate instance
++     */
++    public static final Predicate INSTANCE = new NullPredicate();
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++    public static <T> Predicate<T> getInstance() {
++        return INSTANCE;
++    }
++
++    /**
++     * Restricted constructor.
++     */
++    private NullPredicate() {
++        super();
++    }
++
++    /**
++     * Evaluates the predicate returning true if the input is null.
++     *
++     * @param object the input object
++     * @return true if input is null
++     */
++    public boolean evaluate(T object) {
++        return (object == null);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/OnePredicate.java
+@@ -0,0 +1,113 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++import java.util.Collection;
++
++/**
++ * Predicate implementation that returns true if only one of the predicates return true.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class OnePredicate <T> implements Predicate<T>, PredicateDecorator<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -8125389089924745785L;
++
++    /**
++     * The array of predicates to call
++     */
++    private final Predicate<? super T>[] iPredicates;
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param predicates the predicates to check, cloned, not null
++     * @return the <code>any</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     * @throws IllegalArgumentException if any predicate in the array is null
++     */
++    public static <T> Predicate<T> getInstance(Predicate<? super T>[] predicates) {
++        FunctorUtils.validateMin2(predicates);
++        predicates = FunctorUtils.copy(predicates);
++        return new OnePredicate<T>(predicates);
++    }
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param predicates the predicates to check, cloned, not null
++     * @return the <code>one</code> predicate
++     * @throws IllegalArgumentException if the predicates array is null
++     * @throws IllegalArgumentException if any predicate in the array is null
++     * @throws IllegalArgumentException if the predicates array has less than 2 elements
++     */
++    public static <T> Predicate<T> getInstance(Collection<Predicate<? super T>> predicates) {
++        Predicate[] preds = FunctorUtils.validate(predicates);
++        return new OnePredicate<T>(preds);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicates the predicates to check, not cloned, not null
++     */
++    public OnePredicate(Predicate<? super T>[] predicates) {
++        super();
++        iPredicates = predicates;
++    }
++
++    /**
++     * Evaluates the predicate returning true if only one decorated predicate
++     * returns true.
++     *
++     * @param object the input object
++     * @return true if only one decorated predicate returns true
++     */
++    public boolean evaluate(T object) {
++        boolean match = false;
++        for (int i = 0; i < iPredicates.length; i++) {
++            if (iPredicates[i].evaluate(object)) {
++                if (match) {
++                    return false;
++                }
++                match = true;
++            }
++        }
++        return match;
++    }
++
++    /**
++     * Gets the predicates, do not modify the array.
++     *
++     * @return the predicates
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T>[] getPredicates() {
++        return iPredicates;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/OrPredicate.java
+@@ -0,0 +1,94 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that returns true if either of the predicates return true.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class OrPredicate <T> implements Predicate<T>, PredicateDecorator<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -8791518325735182855L;
++
++    /**
++     * The array of predicates to call
++     */
++    private final Predicate<? super T> iPredicate1;
++    /**
++     * The array of predicates to call
++     */
++    private final Predicate<? super T> iPredicate2;
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param predicate1 the first predicate to check, not null
++     * @param predicate2 the second predicate to check, not null
++     * @return the <code>and</code> predicate
++     * @throws IllegalArgumentException if either predicate is null
++     */
++    public static <T> Predicate<T> getInstance(Predicate<? super T> predicate1, Predicate<? super T> predicate2) {
++        if (predicate1 == null || predicate2 == null) {
++            throw new IllegalArgumentException("Predicate must not be null");
++        }
++        return new OrPredicate<T>(predicate1, predicate2);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicate1 the first predicate to check, not null
++     * @param predicate2 the second predicate to check, not null
++     */
++    public OrPredicate(Predicate<? super T> predicate1, Predicate<? super T> predicate2) {
++        super();
++        iPredicate1 = predicate1;
++        iPredicate2 = predicate2;
++    }
++
++    /**
++     * Evaluates the predicate returning true if either predicate returns true.
++     *
++     * @param object the input object
++     * @return true if either decorated predicate returns true
++     */
++    public boolean evaluate(T object) {
++        return (iPredicate1.evaluate(object) || iPredicate2.evaluate(object));
++    }
++
++    /**
++     * Gets the two predicates being decorated as an array.
++     *
++     * @return the predicates
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T>[] getPredicates() {
++        return new Predicate[]{iPredicate1, iPredicate2};
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/PredicateDecorator.java
+@@ -0,0 +1,42 @@
++// GenericsNote: Converted (no generics required).
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++/**
++ * Defines a predicate that decorates one or more other predicates.
++ * <p/>
++ * This interface enables tools to access the decorated predicates.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.1
++ */
++public interface PredicateDecorator <T> extends Predicate<T> {
++
++    /**
++     * Gets the predicates being decorated as an array.
++     * <p/>
++     * The array may be the internal data structure of the predicate and thus
++     * should not be altered.
++     *
++     * @return the predicates being decorated
++     */
++    Predicate<? super T>[] getPredicates();
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/PredicateTransformer.java
+@@ -0,0 +1,89 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++
++/**
++ * Transformer implementation that calls a Predicate using the input object
++ * and then returns the input.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class PredicateTransformer <T> implements Transformer<T, Boolean>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 5278818408044349346L;
++
++    /**
++     * The closure to wrap
++     */
++    private final Predicate<T> iPredicate;
++
++    /**
++     * Factory method that performs validation.
++     *
++     * @param predicate the predicate to call, not null
++     * @return the <code>predicate</code> transformer
++     * @throws IllegalArgumentException if the predicate is null
++     */
++    public static <T> Transformer<T, Boolean> getInstance(Predicate<T> predicate) {
++        if (predicate == null) {
++            throw new IllegalArgumentException("Predicate must not be null");
++        }
++        return new PredicateTransformer<T>(predicate);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicate the predicate to call, not null
++     */
++    public PredicateTransformer(Predicate<T> predicate) {
++        super();
++        iPredicate = predicate;
++    }
++
++    /**
++     * Transforms the input to result by calling a predicate.
++     *
++     * @param input the input object to transform
++     * @return the transformed result
++     */
++    public Boolean transform(T input) {
++        return (iPredicate.evaluate(input) ? Boolean.TRUE : Boolean.FALSE);
++    }
++
++    /**
++     * Gets the predicate.
++     *
++     * @return the predicate
++     * @since Commons Collections 3.1
++     */
++    public Predicate<T> getPredicate() {
++        return iPredicate;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/PrototypeFactory.java
+@@ -0,0 +1,210 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Factory;
++import org.apache.commons.collections15.FunctorException;
++
++import java.io.*;
++import java.lang.reflect.InvocationTargetException;
++import java.lang.reflect.Method;
++
++/**
++ * Factory implementation that creates a new instance each time based on a prototype.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class PrototypeFactory <T> {
++
++    /**
++     * Factory method that performs validation.
++     * <p/>
++     * Creates a Factory that will return a clone of the same prototype object
++     * each time the factory is used. The prototype will be cloned using one of these
++     * techniques (in order):
++     * <ul>
++     * <li>public clone method
++     * <li>public copy constructor
++     * <li>serialization clone
++     * <ul>
++     *
++     * @param prototype the object to clone each time in the factory
++     * @return the <code>prototype</code> factory
++     * @throws IllegalArgumentException if the prototype is null
++     * @throws IllegalArgumentException if the prototype cannot be cloned
++     */
++    public static <T> Factory<T> getInstance(T prototype) {
++        if (prototype == null) {
++            return ConstantFactory.NULL_INSTANCE;
++        }
++        try {
++            Method method = prototype.getClass().getMethod("clone", null);
++            return new PrototypeCloneFactory<T>(prototype, method);
++
++        } catch (NoSuchMethodException ex) {
++            try {
++                prototype.getClass().getConstructor(new Class[]{prototype.getClass()});
++                return new InstantiateFactory<T>((Class<T>) prototype.getClass(), new Class[]{prototype.getClass()}, new Object[]{prototype});
++
++            } catch (NoSuchMethodException ex2) {
++                if (prototype instanceof Serializable) {
++                    return new PrototypeSerializationFactory((Serializable) prototype);
++                }
++            }
++        }
++        throw new IllegalArgumentException("The prototype must be cloneable via a public clone method");
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     */
++    private PrototypeFactory() {
++        super();
++    }
++
++    // PrototypeCloneFactory
++    //-----------------------------------------------------------------------
++    /**
++     * PrototypeCloneFactory creates objects by copying a prototype using the clone method.
++     */
++    static class PrototypeCloneFactory <T> implements Factory<T>, Serializable {
++
++        /**
++         * The serial version
++         */
++        static final long serialVersionUID = 5604271422565175555L;
++
++        /**
++         * The object to clone each time
++         */
++        private final T iPrototype;
++        /**
++         * The method used to clone
++         */
++        private transient Method iCloneMethod;
++
++        /**
++         * Constructor to store prototype.
++         */
++        private PrototypeCloneFactory(T prototype, Method method) {
++            super();
++            iPrototype = prototype;
++            iCloneMethod = method;
++        }
++
++        /**
++         * Find the Clone method for the class specified.
++         */
++        private void findCloneMethod() {
++            try {
++                iCloneMethod = iPrototype.getClass().getMethod("clone", null);
++
++            } catch (NoSuchMethodException ex) {
++                throw new IllegalArgumentException("PrototypeCloneFactory: The clone method must exist and be public ");
++            }
++        }
++
++        /**
++         * Creates an object by calling the clone method.
++         *
++         * @return the new object
++         */
++        public T create() {
++            // needed for post-serialization
++            if (iCloneMethod == null) {
++                findCloneMethod();
++            }
++
++            try {
++                return (T) iCloneMethod.invoke(iPrototype, null);
++
++            } catch (IllegalAccessException ex) {
++                throw new FunctorException("PrototypeCloneFactory: Clone method must be public", ex);
++            } catch (InvocationTargetException ex) {
++                throw new FunctorException("PrototypeCloneFactory: Clone method threw an exception", ex);
++            }
++        }
++    }
++
++    // PrototypeSerializationFactory
++    //-----------------------------------------------------------------------
++    /**
++     * PrototypeSerializationFactory creates objects by cloning a prototype using serialization.
++     */
++    static class PrototypeSerializationFactory <T extends Serializable> implements Factory<T>, Serializable {
++
++        /**
++         * The serial version
++         */
++        static final long serialVersionUID = -8704966966139178833L;
++
++        /**
++         * The object to clone via serialization each time
++         */
++        private final Serializable iPrototype;
++
++        /**
++         * Constructor to store prototype
++         */
++        private PrototypeSerializationFactory(Serializable prototype) {
++            super();
++            iPrototype = prototype;
++        }
++
++        /**
++         * Creates an object using serialization.
++         *
++         * @return the new object
++         */
++        public T create() {
++            ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
++            ByteArrayInputStream bais = null;
++            try {
++                ObjectOutputStream out = new ObjectOutputStream(baos);
++                out.writeObject(iPrototype);
++
++                bais = new ByteArrayInputStream(baos.toByteArray());
++                ObjectInputStream in = new ObjectInputStream(bais);
++                return (T) in.readObject();
++
++            } catch (ClassNotFoundException ex) {
++                throw new FunctorException(ex);
++            } catch (IOException ex) {
++                throw new FunctorException(ex);
++            } finally {
++                try {
++                    if (bais != null) {
++                        bais.close();
++                    }
++                } catch (IOException ex) {
++                    // ignore
++                }
++                try {
++                    if (baos != null) {
++                        baos.close();
++                    }
++                } catch (IOException ex) {
++                    // ignore
++                }
++            }
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/StringValueTransformer.java
+@@ -0,0 +1,64 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++
++/**
++ * Transformer implementation that returns the <code>String.valueOf</code>.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class StringValueTransformer <T> implements Transformer<T, String>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 7511110693171758606L;
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++    public static <T> Transformer<T, String> getInstance() {
++        return new StringValueTransformer<T>();
++    }
++
++    /**
++     * Restricted constructor.
++     */
++    private StringValueTransformer() {
++        super();
++    }
++
++    /**
++     * Transforms the input to result by calling <code>String.valueOf</code>.
++     *
++     * @param input the input object to transform
++     * @return the transformed result
++     */
++    public String transform(T input) {
++        return String.valueOf(input);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/SwitchClosure.java
+@@ -0,0 +1,182 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Closure;
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++import java.util.Iterator;
++import java.util.Map;
++
++/**
++ * Closure implementation calls the closure whose predicate returns true,
++ * like a switch statement.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class SwitchClosure <T> implements Closure<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 3518477308466486130L;
++
++    /**
++     * The tests to consider
++     */
++    private final Predicate<? super T>[] iPredicates;
++    /**
++     * The matching closures to call
++     */
++    private final Closure<? super T>[] iClosures;
++    /**
++     * The default closure to call if no tests match
++     */
++    private final Closure<? super T> iDefault;
++
++    /**
++     * Factory method that performs validation and copies the parameter arrays.
++     *
++     * @param predicates     array of predicates, cloned, no nulls
++     * @param closures       matching array of closures, cloned, no nulls
++     * @param defaultClosure the closure to use if no match, null means nop
++     * @return the <code>chained</code> closure
++     * @throws IllegalArgumentException if array is null
++     * @throws IllegalArgumentException if any element in the array is null
++     */
++    public static <T> Closure<T> getInstance(Predicate<? super T>[] predicates, Closure<? super T>[] closures, Closure<? super T> defaultClosure) {
++        FunctorUtils.validate(predicates);
++        FunctorUtils.validate(closures);
++        if (predicates.length != closures.length) {
++            throw new IllegalArgumentException("The predicate and closure arrays must be the same size");
++        }
++        if (predicates.length == 0) {
++            return (defaultClosure == null ? NOPClosure.INSTANCE : defaultClosure);
++        }
++        predicates = FunctorUtils.copy(predicates);
++        closures = FunctorUtils.copy(closures);
++        return new SwitchClosure<T>(predicates, closures, defaultClosure);
++    }
++
++    /**
++     * Create a new Closure that calls one of the closures depending
++     * on the predicates.
++     * <p/>
++     * The Map consists of Predicate keys and Closure values. A closure
++     * is called if its matching predicate returns true. Each predicate is evaluated
++     * until one returns true. If no predicates evaluate to true, the default
++     * closure is called. The default closure is set in the map with a
++     * null key. The ordering is that of the iterator() method on the entryset
++     * collection of the map.
++     *
++     * @param predicatesAndClosures a map of predicates to closures
++     * @return the <code>switch</code> closure
++     * @throws IllegalArgumentException if the map is null
++     * @throws IllegalArgumentException if any closure in the map is null
++     * @throws ClassCastException       if the map elements are of the wrong type
++     */
++    public static <T> Closure<T> getInstance(Map<Predicate<? super T>, Closure<? super T>> predicatesAndClosures) {
++        Closure[] closures = null;
++        Predicate[] preds = null;
++        if (predicatesAndClosures == null) {
++            throw new IllegalArgumentException("The predicate and closure map must not be null");
++        }
++        if (predicatesAndClosures.size() == 0) {
++            return NOPClosure.INSTANCE;
++        }
++        // convert to array like this to guarantee iterator() ordering
++        Closure defaultClosure = (Closure) predicatesAndClosures.remove(null);
++        int size = predicatesAndClosures.size();
++        if (size == 0) {
++            return (defaultClosure == null ? NOPClosure.INSTANCE : defaultClosure);
++        }
++        closures = new Closure[size];
++        preds = new Predicate[size];
++        int i = 0;
++        for (Iterator it = predicatesAndClosures.entrySet().iterator(); it.hasNext();) {
++            Map.Entry entry = (Map.Entry) it.next();
++            preds[i] = (Predicate<? super T>) entry.getKey();
++            closures[i] = (Closure<? super T>) entry.getValue();
++            i++;
++        }
++        return new SwitchClosure<T>(preds, closures, defaultClosure);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicates     array of predicates, not cloned, no nulls
++     * @param closures       matching array of closures, not cloned, no nulls
++     * @param defaultClosure the closure to use if no match, null means nop
++     */
++    public SwitchClosure(Predicate<? super T>[] predicates, Closure<? super T>[] closures, Closure<? super T> defaultClosure) {
++        super();
++        iPredicates = predicates;
++        iClosures = closures;
++        iDefault = (defaultClosure == null ? NOPClosure.INSTANCE : defaultClosure);
++    }
++
++    /**
++     * Executes the closure whose matching predicate returns true
++     *
++     * @param input the input object
++     */
++    public void execute(T input) {
++        for (int i = 0; i < iPredicates.length; i++) {
++            if (iPredicates[i].evaluate(input) == true) {
++                iClosures[i].execute(input);
++                return;
++            }
++        }
++        iDefault.execute(input);
++    }
++
++    /**
++     * Gets the predicates, do not modify the array.
++     *
++     * @return the predicates
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T>[] getPredicates() {
++        return iPredicates;
++    }
++
++    /**
++     * Gets the closures, do not modify the array.
++     *
++     * @return the closures
++     * @since Commons Collections 3.1
++     */
++    public Closure<? super T>[] getClosures() {
++        return iClosures;
++    }
++
++    /**
++     * Gets the default closure.
++     *
++     * @return the default closure
++     * @since Commons Collections 3.1
++     */
++    public Closure<? super T> getDefaultClosure() {
++        return iDefault;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/SwitchTransformer.java
+@@ -0,0 +1,183 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++import java.util.Iterator;
++import java.util.Map;
++
++/**
++ * Transformer implementation calls the transformer whose predicate returns true,
++ * like a switch statement.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class SwitchTransformer <I,O> implements Transformer<I, O>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -6404460890903469332L;
++
++    /**
++     * The tests to consider
++     */
++    private final Predicate<? super I>[] iPredicates;
++    /**
++     * The matching transformers to call
++     */
++    private final Transformer<? super I, ? extends O>[] iTransformers;
++    /**
++     * The default transformer to call if no tests match
++     */
++    private final Transformer<? super I, ? extends O> iDefault;
++
++    /**
++     * Factory method that performs validation and copies the parameter arrays.
++     *
++     * @param predicates         array of predicates, cloned, no nulls
++     * @param transformers       matching array of transformers, cloned, no nulls
++     * @param defaultTransformer the transformer to use if no match, null means nop
++     * @return the <code>chained</code> transformer
++     * @throws IllegalArgumentException if array is null
++     * @throws IllegalArgumentException if any element in the array is null
++     */
++    public static <I,O> Transformer<I, O> getInstance(Predicate<? super I>[] predicates, Transformer<? super I, ? extends O>[] transformers, Transformer<? super I, ? extends O> defaultTransformer) {
++        FunctorUtils.validate(predicates);
++        FunctorUtils.validate(transformers);
++        if (predicates.length != transformers.length) {
++            throw new IllegalArgumentException("The predicate and transformer arrays must be the same size");
++        }
++        if (predicates.length == 0) {
++            return (defaultTransformer == null ? ConstantTransformer.NULL_INSTANCE : defaultTransformer);
++        }
++        predicates = FunctorUtils.copy(predicates);
++        transformers = FunctorUtils.copy(transformers);
++        return new SwitchTransformer<I, O>(predicates, transformers, defaultTransformer);
++    }
++
++    /**
++     * Create a new Transformer that calls one of the transformers depending
++     * on the predicates.
++     * <p/>
++     * The Map consists of Predicate keys and Transformer values. A transformer
++     * is called if its matching predicate returns true. Each predicate is evaluated
++     * until one returns true. If no predicates evaluate to true, the default
++     * transformer is called. The default transformer is set in the map with a
++     * null key. The ordering is that of the iterator() method on the entryset
++     * collection of the map.
++     *
++     * @param predicatesAndTransformers a map of predicates to transformers
++     * @return the <code>switch</code> transformer
++     * @throws IllegalArgumentException if the map is null
++     * @throws IllegalArgumentException if any transformer in the map is null
++     * @throws ClassCastException       if the map elements are of the wrong type
++     */
++    public static <I,O> Transformer<I, O> getInstance(Map<Predicate<? super I>, Transformer<? super I, ? extends O>> predicatesAndTransformers) {
++        Transformer<? super I, ? extends O>[] transformers = null;
++        Predicate<? super I>[] preds = null;
++        if (predicatesAndTransformers == null) {
++            throw new IllegalArgumentException("The predicate and transformer map must not be null");
++        }
++        if (predicatesAndTransformers.size() == 0) {
++            return ConstantTransformer.NULL_INSTANCE;
++        }
++        // convert to array like this to guarantee iterator() ordering
++        Transformer<? super I, ? extends O> defaultTransformer = predicatesAndTransformers.remove(null);
++        int size = predicatesAndTransformers.size();
++        if (size == 0) {
++            return (defaultTransformer == null ? ConstantTransformer.NULL_INSTANCE : defaultTransformer);
++        }
++        transformers = new Transformer[size];
++        preds = new Predicate[size];
++        int i = 0;
++        for (Iterator<Map.Entry<Predicate<? super I>, Transformer<? super I, ? extends O>>> it = predicatesAndTransformers.entrySet().iterator(); it.hasNext();) {
++            Map.Entry<Predicate<? super I>, Transformer<? super I, ? extends O>> entry = it.next();
++            preds[i] = entry.getKey();
++            transformers[i] = entry.getValue();
++            i++;
++        }
++        return new SwitchTransformer<I, O>(preds, transformers, defaultTransformer);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicates         array of predicates, not cloned, no nulls
++     * @param transformers       matching array of transformers, not cloned, no nulls
++     * @param defaultTransformer the transformer to use if no match, null means nop
++     */
++    public SwitchTransformer(Predicate<? super I>[] predicates, Transformer<? super I, ? extends O>[] transformers, Transformer<? super I, ? extends O> defaultTransformer) {
++        super();
++        iPredicates = predicates;
++        iTransformers = transformers;
++        iDefault = (defaultTransformer == null ? ConstantTransformer.NULL_INSTANCE : defaultTransformer);
++    }
++
++    /**
++     * Transforms the input to result by calling the transformer whose matching
++     * predicate returns true.
++     *
++     * @param input the input object to transform
++     * @return the transformed result
++     */
++    public O transform(I input) {
++        for (int i = 0; i < iPredicates.length; i++) {
++            if (iPredicates[i].evaluate(input) == true) {
++                return iTransformers[i].transform(input);
++            }
++        }
++        return (O) iDefault.transform(input);
++    }
++
++    /**
++     * Gets the predicates, do not modify the array.
++     *
++     * @return the predicates
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super I>[] getPredicates() {
++        return iPredicates;
++    }
++
++    /**
++     * Gets the transformers, do not modify the array.
++     *
++     * @return the transformers
++     * @since Commons Collections 3.1
++     */
++    public Transformer<? super I, ? extends O>[] getTransformers() {
++        return iTransformers;
++    }
++
++    /**
++     * Gets the default transformer.
++     *
++     * @return the default transformer
++     * @since Commons Collections 3.1
++     */
++    public Transformer<? super I, ? extends O> getDefaultTransformer() {
++        return iDefault;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/TransformedPredicate.java
+@@ -0,0 +1,115 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that transforms the given object before invoking
++ * another <code>Predicate</code>.
++ * <p>
++ * Note: This class cannot suppport generics without breaking the {@link PredicateDecorator} interface.
++ *
++ * @author Matt Hall, John Watkinson, Alban Peignier
++ * @author Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.1
++ */
++public final class TransformedPredicate <I,O> implements Predicate<I>, PredicateDecorator<I>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -5596090919668315834L;
++
++    /**
++     * The transformer to call
++     */
++    private final Transformer<? super I, ? extends O> iTransformer;
++    /**
++     * The predicate to call
++     */
++    private final Predicate<? super O> iPredicate;
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param transformer the transformer to call
++     * @param predicate   the predicate to call with the result of the transform
++     * @return the predicate
++     * @throws IllegalArgumentException if the transformer or the predicate is null
++     */
++    public static <I,O> Predicate<I> getInstance(Transformer<? super I, ? extends O> transformer, Predicate<? super O> predicate) {
++        if (transformer == null) {
++            throw new IllegalArgumentException("The transformer to call must not be null");
++        }
++        if (predicate == null) {
++            throw new IllegalArgumentException("The predicate to call must not be null");
++        }
++        return new TransformedPredicate<I, O>(transformer, predicate);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param transformer the transformer to use
++     * @param predicate   the predicate to decorate
++     */
++    public TransformedPredicate(Transformer<? super I, ? extends O> transformer, Predicate<? super O> predicate) {
++        iTransformer = transformer;
++        iPredicate = predicate;
++    }
++
++    /**
++     * Evaluates the predicate returning the result of the decorated predicate
++     * once the input has been transformed
++     *
++     * @param object the input object which will be transformed
++     * @return true if decorated predicate returns true
++     */
++    public boolean evaluate(I object) {
++        O result = iTransformer.transform(object);
++        return iPredicate.evaluate(result);
++    }
++
++    /**
++     * Gets the predicate being decorated.
++     * <p/>
++     * Not type-safe in 1.5.
++     * <p/>
++     *
++     * @return the predicate as the only element in an array
++     * @since Commons Collections 3.1
++     */
++    public Predicate[] getPredicates() {
++        return new Predicate[]{iPredicate};
++    }
++
++    /**
++     * Gets the transformer in use.
++     *
++     * @return the transformer
++     */
++    public Transformer<? super I, ? extends O> getTransformer() {
++        return iTransformer;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/TransformerClosure.java
+@@ -0,0 +1,89 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Closure;
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++
++/**
++ * Closure implementation that calls a Transformer using the input object
++ * and ignore the result.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class TransformerClosure <I,O> implements Closure<I>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -5194992589193388969L;
++
++    /**
++     * The transformer to wrap
++     */
++    private final Transformer<? super I, O> iTransformer;
++
++    /**
++     * Factory method that performs validation.
++     * <p/>
++     * A null transformer will return the <code>NOPClosure</code>.
++     *
++     * @param transformer the transformer to call, null means nop
++     * @return the <code>transformer</code> closure
++     */
++    public static <I,O> Closure<I> getInstance(Transformer<? super I, O> transformer) {
++        if (transformer == null) {
++            return NOPClosure.INSTANCE;
++        }
++        return new TransformerClosure<I, O>(transformer);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param transformer the transformer to call, not null
++     */
++    public TransformerClosure(Transformer<? super I, O> transformer) {
++        super();
++        iTransformer = transformer;
++    }
++
++    /**
++     * Executes the closure by calling the decorated transformer.
++     *
++     * @param input the input object
++     */
++    public void execute(I input) {
++        iTransformer.transform(input);
++    }
++
++    /**
++     * Gets the transformer.
++     *
++     * @return the transformer
++     * @since Commons Collections 3.1
++     */
++    public Transformer<? super I, O> getTransformer() {
++        return iTransformer;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/TransformerPredicate.java
+@@ -0,0 +1,94 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.FunctorException;
++import org.apache.commons.collections15.Predicate;
++import org.apache.commons.collections15.Transformer;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that returns the result of a transformer.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class TransformerPredicate <T> implements Predicate<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -2407966402920578741L;
++
++    /**
++     * The transformer to call
++     */
++    private final Transformer<T, Boolean> iTransformer;
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @param transformer the transformer to decorate
++     * @return the predicate
++     * @throws IllegalArgumentException if the transformer is null
++     */
++    public static <T> Predicate<T> getInstance(Transformer<T, Boolean> transformer) {
++        if (transformer == null) {
++            throw new IllegalArgumentException("The transformer to call must not be null");
++        }
++        return new TransformerPredicate<T>(transformer);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param transformer the transformer to decorate
++     */
++    public TransformerPredicate(Transformer<T, Boolean> transformer) {
++        super();
++        iTransformer = transformer;
++    }
++
++    /**
++     * Evaluates the predicate returning the result of the decorated transformer.
++     *
++     * @param object the input object
++     * @return true if decorated transformer returns Boolean.TRUE
++     * @throws FunctorException if the transformer returns an invalid type
++     */
++    public boolean evaluate(T object) {
++        Boolean result = iTransformer.transform(object);
++        if (result == null) {
++            throw new FunctorException("Transformer must return an instanceof Boolean, it was a " + (result == null ? "null object" : result.getClass().getName()));
++        }
++        return result.booleanValue();
++    }
++
++    /**
++     * Gets the transformer.
++     *
++     * @return the transformer
++     * @since Commons Collections 3.1
++     */
++    public Transformer<T, Boolean> getTransformer() {
++        return iTransformer;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/TruePredicate.java
+@@ -0,0 +1,69 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Predicate implementation that always returns true.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class TruePredicate <T> implements Predicate<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = 3374767158756189740L;
++
++    /**
++     * Singleton predicate instance
++     */
++    public static final Predicate INSTANCE = new TruePredicate();
++
++    /**
++     * Factory returning the singleton instance.
++     *
++     * @return the singleton instance
++     * @since Commons Collections 3.1
++     */
++    public static <T> Predicate<T> getInstance() {
++        return INSTANCE;
++    }
++
++    /**
++     * Restricted constructor.
++     */
++    private TruePredicate() {
++        super();
++    }
++
++    /**
++     * Evaluates the predicate returning true always.
++     *
++     * @param object the input object
++     * @return true always
++     */
++    public boolean evaluate(T object) {
++        return true;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/UniquePredicate.java
+@@ -0,0 +1,74 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++import java.util.HashSet;
++import java.util.Set;
++
++/**
++ * Predicate implementation that returns true the first time an object is
++ * passed into the predicate.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class UniquePredicate <T> implements Predicate<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -3319417438027438040L;
++
++    /**
++     * The set of previously seen objects
++     */
++    private final Set<T> iSet = new HashSet<T>();
++
++    /**
++     * Factory to create the predicate.
++     *
++     * @return the predicate
++     * @throws IllegalArgumentException if the predicate is null
++     */
++    public static <T> Predicate<T> getInstance() {
++        return new UniquePredicate<T>();
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     */
++    public UniquePredicate() {
++        super();
++    }
++
++    /**
++     * Evaluates the predicate returning true if the input object hasn't been
++     * received yet.
++     *
++     * @param object the input object
++     * @return true if this is the first time the object is seen
++     */
++    public boolean evaluate(T object) {
++        return iSet.add(object);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/WhileClosure.java
+@@ -0,0 +1,130 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.functors;
++
++import org.apache.commons.collections15.Closure;
++import org.apache.commons.collections15.Predicate;
++
++import java.io.Serializable;
++
++/**
++ * Closure implementation that executes a closure repeatedly until a condition is met,
++ * like a do-while or while loop.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class WhileClosure <T> implements Closure<T>, Serializable {
++
++    /**
++     * Serial version UID
++     */
++    static final long serialVersionUID = -3110538116913760108L;
++
++    /**
++     * The test condition
++     */
++    private final Predicate<? super T> iPredicate;
++    /**
++     * The closure to call
++     */
++    private final Closure<? super T> iClosure;
++    /**
++     * The flag, true is a do loop, false is a while
++     */
++    private final boolean iDoLoop;
++
++    /**
++     * Factory method that performs validation.
++     *
++     * @param predicate the predicate used to evaluate when the loop terminates, not null
++     * @param closure   the closure the execute, not null
++     * @param doLoop    true to act as a do-while loop, always executing the closure once
++     * @return the <code>while</code> closure
++     * @throws IllegalArgumentException if the predicate or closure is null
++     */
++    public static <T> Closure<T> getInstance(Predicate<? super T> predicate, Closure<? super T> closure, boolean doLoop) {
++        if (predicate == null) {
++            throw new IllegalArgumentException("Predicate must not be null");
++        }
++        if (closure == null) {
++            throw new IllegalArgumentException("Closure must not be null");
++        }
++        return new WhileClosure<T>(predicate, closure, doLoop);
++    }
++
++    /**
++     * Constructor that performs no validation.
++     * Use <code>getInstance</code> if you want that.
++     *
++     * @param predicate the predicate used to evaluate when the loop terminates, not null
++     * @param closure   the closure the execute, not null
++     * @param doLoop    true to act as a do-while loop, always executing the closure once
++     */
++    public WhileClosure(Predicate<? super T> predicate, Closure<? super T> closure, boolean doLoop) {
++        super();
++        iPredicate = predicate;
++        iClosure = closure;
++        iDoLoop = doLoop;
++    }
++
++    /**
++     * Executes the closure until the predicate is false.
++     *
++     * @param input the input object
++     */
++    public void execute(T input) {
++        if (iDoLoop) {
++            iClosure.execute(input);
++        }
++        while (iPredicate.evaluate(input)) {
++            iClosure.execute(input);
++        }
++    }
++
++    /**
++     * Gets the predicate in use.
++     *
++     * @return the predicate
++     * @since Commons Collections 3.1
++     */
++    public Predicate<? super T> getPredicate() {
++        return iPredicate;
++    }
++
++    /**
++     * Gets the closure.
++     *
++     * @return the closure
++     * @since Commons Collections 3.1
++     */
++    public Closure<? super T> getClosure() {
++        return iClosure;
++    }
++
++    /**
++     * Is the loop a do-while loop.
++     *
++     * @return true is do-while, false if while
++     * @since Commons Collections 3.1
++     */
++    public boolean isDoLoop() {
++        return iDoLoop;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/functors/package.html
+@@ -0,0 +1,26 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:24 pents90 Exp $ -->
++ <!--
++   Copyright 2003-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<BODY>
++<p>
++This package contains implementations of the
++{@link org.apache.commons.collections.Closure Closure},
++{@link org.apache.commons.collections.Predicate Predicate},
++{@link org.apache.commons.collections.Predicate Transformer} and
++{@link org.apache.commons.collections.Predicate Factory} interfaces.
++These provide simple callbacks for processing with collections.
++</pre>
++</BODY>
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/AbstractEmptyIterator.java
+@@ -0,0 +1,89 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import java.util.NoSuchElementException;
++
++/**
++ * Provides an implementation of an empty iterator.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.1
++ */
++abstract class AbstractEmptyIterator <E> {
++
++    /**
++     * Constructor.
++     */
++    protected AbstractEmptyIterator() {
++        super();
++    }
++
++    public boolean hasNext() {
++        return false;
++    }
++
++    public E next() {
++        throw new NoSuchElementException("Iterator contains no elements");
++    }
++
++    public boolean hasPrevious() {
++        return false;
++    }
++
++    public E previous() {
++        throw new NoSuchElementException("Iterator contains no elements");
++    }
++
++    public int nextIndex() {
++        return 0;
++    }
++
++    public int previousIndex() {
++        return -1;
++    }
++
++    public void add(E obj) {
++        throw new UnsupportedOperationException("add() not supported for empty Iterator");
++    }
++
++    public void set(E obj) {
++        throw new IllegalStateException("Iterator contains no elements");
++    }
++
++    public void remove() {
++        throw new IllegalStateException("Iterator contains no elements");
++    }
++
++    public E getKey() {
++        throw new IllegalStateException("Iterator contains no elements");
++    }
++
++    public E getValue() {
++        throw new IllegalStateException("Iterator contains no elements");
++    }
++
++    public E setValue(E value) {
++        throw new IllegalStateException("Iterator contains no elements");
++    }
++
++    public void reset() {
++        // do nothing
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/AbstractIteratorDecorator.java
+@@ -0,0 +1,75 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import java.util.Iterator;
++
++/**
++ * Provides basic behaviour for decorating an iterator with extra functionality.
++ * <p/>
++ * All methods are forwarded to the decorated iterator.
++ *
++ * @author Matt Hall, John Watkinson, James Strachan
++ * @author Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class AbstractIteratorDecorator <E> implements Iterator<E> {
++
++    /**
++     * The iterator being decorated
++     */
++    protected final Iterator<E> iterator;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that decorates the specified iterator.
++     *
++     * @param iterator the iterator to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    public AbstractIteratorDecorator(Iterator<E> iterator) {
++        super();
++        if (iterator == null) {
++            throw new IllegalArgumentException("Iterator must not be null");
++        }
++        this.iterator = iterator;
++    }
++
++    /**
++     * Gets the iterator being decorated.
++     *
++     * @return the decorated iterator
++     */
++    protected Iterator<E> getIterator() {
++        return iterator;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean hasNext() {
++        return iterator.hasNext();
++    }
++
++    public E next() {
++        return iterator.next();
++    }
++
++    public void remove() {
++        iterator.remove();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/AbstractListIteratorDecorator.java
+@@ -0,0 +1,99 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import java.util.ListIterator;
++
++/**
++ * Provides basic behaviour for decorating a list iterator with extra functionality.
++ * <p/>
++ * All methods are forwarded to the decorated list iterator.
++ *
++ * @author Rodney Waldhoff
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class AbstractListIteratorDecorator <E> implements ListIterator<E> {
++
++    /**
++     * The iterator being decorated
++     */
++    protected final ListIterator<E> iterator;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that decorates the specified iterator.
++     *
++     * @param iterator the iterator to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    public AbstractListIteratorDecorator(ListIterator<E> iterator) {
++        super();
++        if (iterator == null) {
++            throw new IllegalArgumentException("ListIterator must not be null");
++        }
++        this.iterator = iterator;
++    }
++
++    /**
++     * Gets the iterator being decorated.
++     *
++     * @return the decorated iterator
++     */
++    protected ListIterator<E> getListIterator() {
++        return iterator;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean hasNext() {
++        return iterator.hasNext();
++    }
++
++    public E next() {
++        return iterator.next();
++    }
++
++    public int nextIndex() {
++        return iterator.nextIndex();
++    }
++
++    public boolean hasPrevious() {
++        return iterator.hasPrevious();
++    }
++
++    public E previous() {
++        return iterator.previous();
++    }
++
++    public int previousIndex() {
++        return iterator.previousIndex();
++    }
++
++    public void remove() {
++        iterator.remove();
++    }
++
++    public void set(E obj) {
++        iterator.set(obj);
++    }
++
++    public void add(E obj) {
++        iterator.add(obj);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/AbstractMapIteratorDecorator.java
+@@ -0,0 +1,86 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.MapIterator;
++
++/**
++ * Provides basic behaviour for decorating a map iterator with extra functionality.
++ * <p/>
++ * All methods are forwarded to the decorated map iterator.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class AbstractMapIteratorDecorator <K,V> implements MapIterator<K, V> {
++
++    /**
++     * The iterator being decorated
++     */
++    protected final MapIterator<K, V> iterator;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that decorates the specified iterator.
++     *
++     * @param iterator the iterator to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    public AbstractMapIteratorDecorator(MapIterator<K, V> iterator) {
++        super();
++        if (iterator == null) {
++            throw new IllegalArgumentException("MapIterator must not be null");
++        }
++        this.iterator = iterator;
++    }
++
++    /**
++     * Gets the iterator being decorated.
++     *
++     * @return the decorated iterator
++     */
++    protected MapIterator<K, V> getMapIterator() {
++        return iterator;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean hasNext() {
++        return iterator.hasNext();
++    }
++
++    public K next() {
++        return iterator.next();
++    }
++
++    public void remove() {
++        iterator.remove();
++    }
++
++    public K getKey() {
++        return iterator.getKey();
++    }
++
++    public V getValue() {
++        return iterator.getValue();
++    }
++
++    public V setValue(V obj) {
++        return iterator.setValue(obj);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/AbstractOrderedMapIteratorDecorator.java
+@@ -0,0 +1,94 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.OrderedMapIterator;
++
++/**
++ * Provides basic behaviour for decorating an ordered map iterator with extra functionality.
++ * <p/>
++ * All methods are forwarded to the decorated map iterator.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class AbstractOrderedMapIteratorDecorator <K,V> implements OrderedMapIterator<K, V> {
++
++    /**
++     * The iterator being decorated
++     */
++    protected final OrderedMapIterator<K, V> iterator;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that decorates the specified iterator.
++     *
++     * @param iterator the iterator to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    public AbstractOrderedMapIteratorDecorator(OrderedMapIterator<K, V> iterator) {
++        super();
++        if (iterator == null) {
++            throw new IllegalArgumentException("OrderedMapIterator must not be null");
++        }
++        this.iterator = iterator;
++    }
++
++    /**
++     * Gets the iterator being decorated.
++     *
++     * @return the decorated iterator
++     */
++    protected OrderedMapIterator<K, V> getOrderedMapIterator() {
++        return iterator;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean hasNext() {
++        return iterator.hasNext();
++    }
++
++    public K next() {
++        return iterator.next();
++    }
++
++    public boolean hasPrevious() {
++        return iterator.hasPrevious();
++    }
++
++    public K previous() {
++        return iterator.previous();
++    }
++
++    public void remove() {
++        iterator.remove();
++    }
++
++    public K getKey() {
++        return iterator.getKey();
++    }
++
++    public V getValue() {
++        return iterator.getValue();
++    }
++
++    public V setValue(V obj) {
++        return iterator.setValue(obj);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/ArrayIterator.java
+@@ -0,0 +1,224 @@
++// GenericsNote: Converted, although unsatisfying because there does not seem to be a way to generify the primitive types.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.ResettableIterator;
++
++import java.lang.reflect.Array;
++import java.util.NoSuchElementException;
++
++/**
++ * Implements an {@link java.util.Iterator Iterator} over any array.
++ * <p/>
++ * The array can be either an array of object or of primitives. If you know
++ * that you have an object array, the
++ * {@link org.apache.commons.collections15.iterators.ObjectArrayIterator ObjectArrayIterator}
++ * class is a better choice, as it will perform better.
++ * <p/>
++ * The iterator implements a {@link #reset} method, allowing the reset of
++ * the iterator back to the start if required.
++ *
++ * @author James Strachan
++ * @author Mauricio S. Moura
++ * @author Michael A. Smith
++ * @author Neil O'Toole
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 1.0
++ */
++public class ArrayIterator <E> implements ResettableIterator<E> {
++
++    /**
++     * The array to iterate over
++     */
++    protected Object array;
++    /**
++     * The start index to loop from
++     */
++    protected int startIndex = 0;
++    /**
++     * The end index to loop to
++     */
++    protected int endIndex = 0;
++    /**
++     * The current iterator index
++     */
++    protected int index = 0;
++    
++    // Constructors
++    // ----------------------------------------------------------------------
++    /**
++     * Constructor for use with <code>setArray</code>.
++     * <p/>
++     * Using this constructor, the iterator is equivalent to an empty iterator
++     * until {@link #setArray(Object)} is  called to establish the array to iterate over.
++     */
++    public ArrayIterator() {
++        super();
++    }
++
++    /**
++     * Constructs an ArrayIterator that will iterate over the values in the
++     * specified array.
++     *
++     * @param array the array to iterate over.
++     * @throws IllegalArgumentException if <code>array</code> is not an array.
++     * @throws NullPointerException     if <code>array</code> is <code>null</code>
++     */
++    public ArrayIterator(final Object array) {
++        super();
++        setArray(array);
++    }
++
++    /**
++     * Constructs an ArrayIterator that will iterate over the values in the
++     * specified array from a specific start index.
++     *
++     * @param array      the array to iterate over.
++     * @param startIndex the index to start iterating at.
++     * @throws IllegalArgumentException  if <code>array</code> is not an array.
++     * @throws NullPointerException      if <code>array</code> is <code>null</code>
++     * @throws IndexOutOfBoundsException if the index is invalid
++     */
++    public ArrayIterator(final Object array, final int startIndex) {
++        super();
++        setArray(array);
++        checkBound(startIndex, "start");
++        this.startIndex = startIndex;
++        this.index = startIndex;
++    }
++
++    /**
++     * Construct an ArrayIterator that will iterate over a range of values
++     * in the specified array.
++     *
++     * @param array      the array to iterate over.
++     * @param startIndex the index to start iterating at.
++     * @param endIndex   the index to finish iterating at.
++     * @throws IllegalArgumentException  if <code>array</code> is not an array.
++     * @throws NullPointerException      if <code>array</code> is <code>null</code>
++     * @throws IndexOutOfBoundsException if either index is invalid
++     */
++    public ArrayIterator(final Object array, final int startIndex, final int endIndex) {
++        super();
++        setArray(array);
++        checkBound(startIndex, "start");
++        checkBound(endIndex, "end");
++        if (endIndex < startIndex) {
++            throw new IllegalArgumentException("End index must not be less than start index.");
++        }
++        this.startIndex = startIndex;
++        this.endIndex = endIndex;
++        this.index = startIndex;
++    }
++
++    /**
++     * Checks whether the index is valid or not.
++     *
++     * @param bound the index to check
++     * @param type  the index type (for error messages)
++     * @throws IndexOutOfBoundsException if the index is invalid
++     */
++    protected void checkBound(final int bound, final String type) {
++        if (bound > this.endIndex) {
++            throw new ArrayIndexOutOfBoundsException("Attempt to make an ArrayIterator that " + type + "s beyond the end of the array. ");
++        }
++        if (bound < 0) {
++            throw new ArrayIndexOutOfBoundsException("Attempt to make an ArrayIterator that " + type + "s before the start of the array. ");
++        }
++    }
++
++    // Iterator interface
++    //-----------------------------------------------------------------------
++    /**
++     * Returns true if there are more elements to return from the array.
++     *
++     * @return true if there is a next element to return
++     */
++    public boolean hasNext() {
++        return (index < endIndex);
++    }
++
++    /**
++     * Returns the next element in the array.
++     *
++     * @return the next element in the array
++     * @throws NoSuchElementException if all the elements in the array
++     *                                have already been returned
++     */
++    public E next() {
++        if (hasNext() == false) {
++            throw new NoSuchElementException();
++        }
++        return (E) Array.get(array, index++);
++    }
++
++    /**
++     * Throws {@link UnsupportedOperationException}.
++     *
++     * @throws UnsupportedOperationException always
++     */
++    public void remove() {
++        throw new UnsupportedOperationException("remove() method is not supported");
++    }
++
++    // Properties
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the array that this iterator is iterating over.
++     *
++     * @return the array this iterator iterates over, or <code>null</code> if
++     *         the no-arg constructor was used and {@link #setArray(Object)} has never
++     *         been called with a valid array.
++     */
++    public Object getArray() {
++        return array;
++    }
++
++    /**
++     * Sets the array that the ArrayIterator should iterate over.
++     * <p/>
++     * If an array has previously been set (using the single-arg constructor
++     * or this method) then that array is discarded in favour of this one.
++     * Iteration is restarted at the start of the new array.
++     * Although this can be used to reset iteration, the {@link #reset()} method
++     * is a more effective choice.
++     *
++     * @param array the array that the iterator should iterate over.
++     * @throws IllegalArgumentException if <code>array</code> is not an array.
++     * @throws NullPointerException     if <code>array</code> is <code>null</code>
++     */
++    public void setArray(final Object array) {
++        // Array.getLength throws IllegalArgumentException if the object is not
++        // an array or NullPointerException if the object is null.  This call
++        // is made before saving the array and resetting the index so that the
++        // array iterator remains in a consistent state if the argument is not
++        // an array or is null.
++        this.endIndex = Array.getLength(array);
++        this.startIndex = 0;
++        this.array = array;
++        this.index = 0;
++    }
++
++    /**
++     * Resets the iterator back to the start index.
++     */
++    public void reset() {
++        this.index = this.startIndex;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/ArrayListIterator.java
+@@ -0,0 +1,210 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.ResettableListIterator;
++
++import java.lang.reflect.Array;
++import java.util.ListIterator;
++import java.util.NoSuchElementException;
++
++/**
++ * Implements a {@link ListIterator} over an array.
++ * <p/>
++ * The array can be either an array of object or of primitives. If you know
++ * that you have an object array, the {@link ObjectArrayListIterator}
++ * class is a better choice, as it will perform better.
++ * <p/>
++ * <p/>
++ * This iterator does not support {@link #add(Object)} or {@link #remove()}, as the array
++ * cannot be changed in size. The {@link #set(Object)} method is supported however.
++ *
++ * @author Neil O'Toole
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Phil Steitz
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @see org.apache.commons.collections15.iterators.ArrayIterator
++ * @see java.util.Iterator
++ * @see java.util.ListIterator
++ * @since Commons Collections 3.0
++ */
++public class ArrayListIterator <E> extends ArrayIterator<E> implements ListIterator<E>, ResettableListIterator<E> {
++
++    /**
++     * Holds the index of the last item returned by a call to <code>next()</code>
++     * or <code>previous()</code>. This is set to <code>-1</code> if neither method
++     * has yet been invoked. <code>lastItemIndex</code> is used to to implement
++     * the {@link #set} method.
++     */
++    protected int lastItemIndex = -1;
++
++    // Constructors
++    // ----------------------------------------------------------------------
++    /**
++     * Constructor for use with <code>setArray</code>.
++     * <p/>
++     * Using this constructor, the iterator is equivalent to an empty iterator
++     * until {@link #setArray(Object)} is  called to establish the array to iterate over.
++     */
++    public ArrayListIterator() {
++        super();
++    }
++
++    /**
++     * Constructs an ArrayListIterator that will iterate over the values in the
++     * specified array.
++     *
++     * @param array the array to iterate over
++     * @throws IllegalArgumentException if <code>array</code> is not an array.
++     * @throws NullPointerException     if <code>array</code> is <code>null</code>
++     */
++    public ArrayListIterator(Object array) {
++        super(array);
++    }
++
++    /**
++     * Constructs an ArrayListIterator that will iterate over the values in the
++     * specified array from a specific start index.
++     *
++     * @param array      the array to iterate over
++     * @param startIndex the index to start iterating at
++     * @throws IllegalArgumentException  if <code>array</code> is not an array.
++     * @throws NullPointerException      if <code>array</code> is <code>null</code>
++     * @throws IndexOutOfBoundsException if the start index is out of bounds
++     */
++    public ArrayListIterator(Object array, int startIndex) {
++        super(array, startIndex);
++        this.startIndex = startIndex;
++    }
++
++    /**
++     * Construct an ArrayListIterator that will iterate over a range of values
++     * in the specified array.
++     *
++     * @param array      the array to iterate over
++     * @param startIndex the index to start iterating at
++     * @param endIndex   the index (exclusive) to finish iterating at
++     * @throws IllegalArgumentException  if <code>array</code> is not an array.
++     * @throws IndexOutOfBoundsException if the start or end index is out of bounds
++     * @throws IllegalArgumentException  if end index is before the start
++     * @throws NullPointerException      if <code>array</code> is <code>null</code>
++     */
++    public ArrayListIterator(Object array, int startIndex, int endIndex) {
++        super(array, startIndex, endIndex);
++        this.startIndex = startIndex;
++    }
++
++    // ListIterator interface
++    //-----------------------------------------------------------------------
++    /**
++     * Returns true if there are previous elements to return from the array.
++     *
++     * @return true if there is a previous element to return
++     */
++    public boolean hasPrevious() {
++        return (this.index > this.startIndex);
++    }
++
++    /**
++     * Gets the previous element from the array.
++     *
++     * @return the previous element
++     * @throws NoSuchElementException if there is no previous element
++     */
++    public E previous() {
++        if (hasPrevious() == false) {
++            throw new NoSuchElementException();
++        }
++        this.lastItemIndex = --this.index;
++        return (E) Array.get(this.array, this.index);
++    }
++
++    /**
++     * Gets the next element from the array.
++     *
++     * @return the next element
++     * @throws NoSuchElementException if there is no next element
++     */
++    public E next() {
++        if (hasNext() == false) {
++            throw new NoSuchElementException();
++        }
++        this.lastItemIndex = this.index;
++        return (E) Array.get(this.array, this.index++);
++    }
++
++    /**
++     * Gets the next index to be retrieved.
++     *
++     * @return the index of the item to be retrieved next
++     */
++    public int nextIndex() {
++        return this.index - this.startIndex;
++    }
++
++    /**
++     * Gets the index of the item to be retrieved if {@link #previous()} is called.
++     *
++     * @return the index of the item to be retrieved next
++     */
++    public int previousIndex() {
++        return this.index - this.startIndex - 1;
++    }
++
++    /**
++     * This iterator does not support modification of its backing collection, and so will
++     * always throw an {@link UnsupportedOperationException} when this method is invoked.
++     *
++     * @throws UnsupportedOperationException always thrown.
++     * @see java.util.ListIterator#set
++     */
++    public void add(E o) {
++        throw new UnsupportedOperationException("add() method is not supported");
++    }
++
++    /**
++     * Sets the element under the cursor.
++     * <p/>
++     * This method sets the element that was returned by the last call
++     * to {@link #next()} of {@link #previous()}.
++     * <p/>
++     * <b>Note:</b> {@link ListIterator} implementations that support
++     * <code>add()</code> and <code>remove()</code> only allow <code>set()</code> to be called
++     * once per call to <code>next()</code> or <code>previous</code> (see the {@link ListIterator}
++     * javadoc for more details). Since this implementation does
++     * not support <code>add()</code> or <code>remove()</code>, <code>set()</code> may be
++     * called as often as desired.
++     *
++     * @see java.util.ListIterator#set
++     */
++    public void set(E o) {
++        if (this.lastItemIndex == -1) {
++            throw new IllegalStateException("must call next() or previous() before a call to set()");
++        }
++
++        Array.set(this.array, this.lastItemIndex, o);
++    }
++
++    /**
++     * Resets the iterator back to the start index.
++     */
++    public void reset() {
++        super.reset();
++        this.lastItemIndex = -1;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/CollatingIterator.java
+@@ -0,0 +1,374 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.list.UnmodifiableList;
++
++import java.util.*;
++
++/**
++ * Provides an ordered iteration over the elements contained in
++ * a collection of ordered Iterators.
++ * <p/>
++ * Given two ordered {@link Iterator} instances <code>A</code> and <code>B</code>,
++ * the {@link #next} method on this iterator will return the lesser of
++ * <code>A.next()</code> and <code>B.next()</code>.
++ *
++ * @author Rodney Waldhoff
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 2.1
++ */
++public class CollatingIterator <E> implements Iterator<E> {
++
++    /**
++     * The {@link Comparator} used to evaluate order.
++     */
++    private Comparator<? super E> comparator = null;
++
++    /**
++     * The list of {@link Iterator}s to evaluate.
++     */
++    private ArrayList<Iterator<? extends E>> iterators = null;
++
++    /**
++     * {@link Iterator#next Next} objects peeked from each iterator.
++     */
++    private ArrayList<E> values = null;
++
++    /**
++     * Whether or not each {@link #values} element has been set.
++     */
++    private BitSet valueSet = null;
++
++    /**
++     * Index of the {@link #iterators iterator} from whom the last returned value was obtained.
++     */
++    private int lastReturned = -1;
++
++    // Constructors
++    // ----------------------------------------------------------------------
++    /**
++     * Constructs a new <code>CollatingIterator</code>.  Natural sort order
++     * will be used, and child iterators will have to be manually added
++     * using the {@link #addIterator(Iterator)} method.
++     */
++    public CollatingIterator() {
++        this(null, 2);
++    }
++
++    /**
++     * Constructs a new <code>CollatingIterator</code> that will used the
++     * specified comparator for ordering.  Child iterators will have to be
++     * manually added using the {@link #addIterator(Iterator)} method.
++     *
++     * @param comp the comparator to use to sort, or null to use natural sort order
++     */
++    public CollatingIterator(final Comparator<? super E> comp) {
++        this(comp, 2);
++    }
++
++    /**
++     * Constructs a new <code>CollatingIterator</code> that will used the
++     * specified comparator for ordering and have the specified initial
++     * capacity.  Child iterators will have to be
++     * manually added using the {@link #addIterator(Iterator)} method.
++     *
++     * @param comp             the comparator to use to sort, or null to use natural sort order
++     * @param initIterCapacity the initial capacity for the internal list
++     *                         of child iterators
++     */
++    public CollatingIterator(final Comparator<? super E> comp, final int initIterCapacity) {
++        iterators = new ArrayList<Iterator<? extends E>>(initIterCapacity);
++        setComparator(comp);
++    }
++
++    /**
++     * Constructs a new <code>CollatingIterator</code> that will use the
++     * specified comparator to provide ordered iteration over the two
++     * given iterators.
++     *
++     * @param comp the comparator to use to sort, or null to use natural sort order
++     * @param a    the first child ordered iterator
++     * @param b    the second child ordered iterator
++     * @throws NullPointerException if either iterator is null
++     */
++    public CollatingIterator(final Comparator<? super E> comp, final Iterator<? extends E> a, final Iterator<? extends E> b) {
++        this(comp, 2);
++        addIterator(a);
++        addIterator(b);
++    }
++
++    /**
++     * Constructs a new <code>CollatingIterator</code> that will use the
++     * specified comparator to provide ordered iteration over the array
++     * of iterators.
++     *
++     * @param comp      the comparator to use to sort, or null to use natural sort order
++     * @param iterators the array of iterators
++     * @throws NullPointerException if iterators array is or contains null
++     */
++    public CollatingIterator(final Comparator<? super E> comp, final Iterator<? extends E>[] iterators) {
++        this(comp, iterators.length);
++        for (int i = 0; i < iterators.length; i++) {
++            addIterator(iterators[i]);
++        }
++    }
++
++    /**
++     * Constructs a new <code>CollatingIterator</code> that will use the
++     * specified comparator to provide ordered iteration over the collection
++     * of iterators.
++     *
++     * @param comp      the comparator to use to sort, or null to use natural sort order
++     * @param iterators the collection of iterators
++     * @throws NullPointerException if the iterators collection is or contains null
++     * @throws ClassCastException   if the iterators collection contains an
++     *                              element that's not an {@link Iterator}
++     */
++    public CollatingIterator(final Comparator<? super E> comp, final Collection<Iterator<? extends E>> iterators) {
++        this(comp, iterators.size());
++        for (Iterator<Iterator<? extends E>> it = iterators.iterator(); it.hasNext();) {
++            Iterator<? extends E> item = it.next();
++            addIterator(item);
++        }
++    }
++
++    // Public Methods
++    // ----------------------------------------------------------------------
++    /**
++     * Adds the given {@link Iterator} to the iterators being collated.
++     *
++     * @param iterator the iterator to add to the collation, must not be null
++     * @throws IllegalStateException if iteration has started
++     * @throws NullPointerException  if the iterator is null
++     */
++    public void addIterator(final Iterator<? extends E> iterator) {
++        checkNotStarted();
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        iterators.add(iterator);
++    }
++
++    /**
++     * Sets the iterator at the given index.
++     *
++     * @param index    index of the Iterator to replace
++     * @param iterator Iterator to place at the given index
++     * @throws IndexOutOfBoundsException if index < 0 or index > size()
++     * @throws IllegalStateException     if iteration has started
++     * @throws NullPointerException      if the iterator is null
++     */
++    public void setIterator(final int index, final Iterator<? extends E> iterator) {
++        checkNotStarted();
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        iterators.set(index, iterator);
++    }
++
++    /**
++     * Gets the list of Iterators (unmodifiable).
++     *
++     * @return the unmodifiable list of iterators added
++     */
++    public List<Iterator<? extends E>> getIterators() {
++        return UnmodifiableList.decorate(iterators);
++    }
++
++    /**
++     * Gets the {@link Comparator} by which collatation occurs.
++     */
++    public Comparator<? super E> getComparator() {
++        return comparator;
++    }
++
++    /**
++     * Sets the {@link Comparator} by which collation occurs.
++     *
++     * @throws IllegalStateException if iteration has started
++     */
++    public void setComparator(final Comparator<? super E> comp) {
++        checkNotStarted();
++        comparator = comp;
++    }
++
++    // Iterator Methods
++    // -------------------------------------------------------------------
++    /**
++     * Returns <code>true</code> if any child iterator has remaining elements.
++     *
++     * @return true if this iterator has remaining elements
++     */
++    public boolean hasNext() {
++        start();
++        return anyValueSet(valueSet) || anyHasNext(iterators);
++    }
++
++    /**
++     * Returns the next ordered element from a child iterator.
++     *
++     * @return the next ordered element
++     * @throws NoSuchElementException if no child iterator has any more elements
++     */
++    public E next() throws NoSuchElementException {
++        if (hasNext() == false) {
++            throw new NoSuchElementException();
++        }
++        int leastIndex = least();
++        if (leastIndex == -1) {
++            throw new NoSuchElementException();
++        } else {
++            E val = values.get(leastIndex);
++            clear(leastIndex);
++            lastReturned = leastIndex;
++            return val;
++        }
++    }
++
++    /**
++     * Removes the last returned element from the child iterator that
++     * produced it.
++     *
++     * @throws IllegalStateException if there is no last returned element,
++     *                               or if the last returned element has already been removed
++     */
++    public void remove() {
++        if (lastReturned == -1) {
++            throw new IllegalStateException("No value can be removed at present");
++        }
++        Iterator<? extends E> it = iterators.get(lastReturned);
++        it.remove();
++    }
++
++    // Private Methods
++    // -------------------------------------------------------------------
++    /**
++     * Initializes the collating state if it hasn't been already.
++     */
++    private void start() {
++        if (values == null) {
++            values = new ArrayList<E>(iterators.size());
++            valueSet = new BitSet(iterators.size());
++            for (int i = 0; i < iterators.size(); i++) {
++                values.add(null);
++                valueSet.clear(i);
++            }
++        }
++    }
++
++    /**
++     * Sets the {@link #values} and {@link #valueSet} attributes
++     * at position <i>i</i> to the next value of the
++     * {@link #iterators iterator} at position <i>i</i>, or
++     * clear them if the <i>i</i><sup>th</sup> iterator
++     * has no next value.
++     *
++     * @return <tt>false</tt> iff there was no value to set
++     */
++    private boolean set(int i) {
++        Iterator<? extends E> it = iterators.get(i);
++        if (it.hasNext()) {
++            values.set(i, it.next());
++            valueSet.set(i);
++            return true;
++        } else {
++            values.set(i, null);
++            valueSet.clear(i);
++            return false;
++        }
++    }
++
++    /**
++     * Clears the {@link #values} and {@link #valueSet} attributes
++     * at position <i>i</i>.
++     */
++    private void clear(int i) {
++        values.set(i, null);
++        valueSet.clear(i);
++    }
++
++    /**
++     * Throws {@link IllegalStateException} if iteration has started
++     * via {@link #start}.
++     *
++     * @throws IllegalStateException if iteration started
++     */
++    private void checkNotStarted() throws IllegalStateException {
++        if (values != null) {
++            throw new IllegalStateException("Can't do that after next or hasNext has been called.");
++        }
++    }
++
++    /**
++     * Returns the index of the least element in {@link #values},
++     * {@link #set(int) setting} any uninitialized values.
++     *
++     * @throws IllegalStateException
++     */
++    private int least() {
++        int leastIndex = -1;
++        E leastObject = null;
++        for (int i = 0; i < values.size(); i++) {
++            if (valueSet.get(i) == false) {
++                set(i);
++            }
++            if (valueSet.get(i)) {
++                if (leastIndex == -1) {
++                    leastIndex = i;
++                    leastObject = values.get(i);
++                } else {
++                    E curObject = values.get(i);
++                    if (comparator.compare(curObject, leastObject) < 0) {
++                        leastObject = curObject;
++                        leastIndex = i;
++                    }
++                }
++            }
++        }
++        return leastIndex;
++    }
++
++    /**
++     * Returns <code>true</code> iff any bit in the given set is
++     * <code>true</code>.
++     */
++    private boolean anyValueSet(BitSet set) {
++        for (int i = 0; i < set.size(); i++) {
++            if (set.get(i)) {
++                return true;
++            }
++        }
++        return false;
++    }
++
++    /**
++     * Returns <code>true</code> iff any {@link Iterator}
++     * in the given list has a next value.
++     */
++    private boolean anyHasNext(ArrayList<Iterator<? extends E>> iters) {
++        for (int i = 0; i < iters.size(); i++) {
++            Iterator<? extends E> it = iters.get(i);
++            if (it.hasNext()) {
++                return true;
++            }
++        }
++        return false;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/EmptyIterator.java
+@@ -0,0 +1,60 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.ResettableIterator;
++
++import java.util.Iterator;
++
++/**
++ * Provides an implementation of an empty iterator.
++ * <p/>
++ * This class provides an implementation of an empty iterator.
++ * This class provides for binary compatability between Commons Collections
++ * 2.1.1 and 3.1 due to issues with <code>IteratorUtils</code>.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 2.1.1 and 3.1
++ */
++public class EmptyIterator <E> extends AbstractEmptyIterator<E> implements ResettableIterator<E> {
++
++    /**
++     * Singleton instance of the iterator.
++     *
++     * @since Commons Collections 3.1
++     */
++    public static final ResettableIterator RESETTABLE_INSTANCE = new EmptyIterator();
++    /**
++     * Singleton instance of the iterator.
++     *
++     * @since Commons Collections 2.1.1 and 3.1
++     */
++    public static final Iterator INSTANCE = RESETTABLE_INSTANCE;
++
++	public static <T> Iterator<T> getInstance() {
++		return INSTANCE;
++	}
++	
++    /**
++     * Constructor.
++     */
++    protected EmptyIterator() {
++        super();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/EmptyListIterator.java
+@@ -0,0 +1,56 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.ResettableListIterator;
++
++import java.util.ListIterator;
++
++/**
++ * Provides an implementation of an empty list iterator.
++ * <p/>
++ * This class provides an implementation of an empty list iterator.
++ * This class provides for binary compatability between Commons Collections
++ * 2.1.1 and 3.1 due to issues with <code>IteratorUtils</code>.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 2.1.1 and 3.1
++ */
++public class EmptyListIterator <E> extends AbstractEmptyIterator<E> implements ResettableListIterator<E> {
++
++    /**
++     * Singleton instance of the iterator.
++     *
++     * @since Commons Collections 3.1
++     */
++    public static final ResettableListIterator RESETTABLE_INSTANCE = new EmptyListIterator();
++    /**
++     * Singleton instance of the iterator.
++     *
++     * @since Commons Collections 2.1.1 and 3.1
++     */
++    public static final ListIterator INSTANCE = RESETTABLE_INSTANCE;
++
++    /**
++     * Constructor.
++     */
++    protected EmptyListIterator() {
++        super();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/EmptyMapIterator.java
+@@ -0,0 +1,45 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.ResettableIterator;
++
++/**
++ * Provides an implementation of an empty map iterator.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.1
++ */
++public class EmptyMapIterator extends AbstractEmptyIterator implements MapIterator, ResettableIterator {
++
++    /**
++     * Singleton instance of the iterator.
++     *
++     * @since Commons Collections 3.1
++     */
++    public static final MapIterator INSTANCE = new EmptyMapIterator();
++
++    /**
++     * Constructor.
++     */
++    protected EmptyMapIterator() {
++        super();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/EmptyOrderedIterator.java
+@@ -0,0 +1,45 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.OrderedIterator;
++import org.apache.commons.collections15.ResettableIterator;
++
++/**
++ * Provides an implementation of an empty ordered iterator.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.1
++ */
++public class EmptyOrderedIterator <E> extends AbstractEmptyIterator<E> implements OrderedIterator<E>, ResettableIterator<E> {
++
++    /**
++     * Singleton instance of the iterator.
++     *
++     * @since Commons Collections 3.1
++     */
++    public static final OrderedIterator INSTANCE = new EmptyOrderedIterator();
++
++    /**
++     * Constructor.
++     */
++    protected EmptyOrderedIterator() {
++        super();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/EmptyOrderedMapIterator.java
+@@ -0,0 +1,45 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.OrderedMapIterator;
++import org.apache.commons.collections15.ResettableIterator;
++
++/**
++ * Provides an implementation of an empty ordered map iterator.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.1
++ */
++public class EmptyOrderedMapIterator extends AbstractEmptyIterator implements OrderedMapIterator, ResettableIterator {
++
++    /**
++     * Singleton instance of the iterator.
++     *
++     * @since Commons Collections 3.1
++     */
++    public static final OrderedMapIterator INSTANCE = new EmptyOrderedMapIterator();
++
++    /**
++     * Constructor.
++     */
++    protected EmptyOrderedMapIterator() {
++        super();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/EntrySetMapIterator.java
+@@ -0,0 +1,171 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.ResettableIterator;
++
++import java.util.Iterator;
++import java.util.Map;
++
++/**
++ * Implements a <code>MapIterator</code> using a Map entrySet.
++ * Reverse iteration is not supported.
++ * <pre>
++ * MapIterator it = map.mapIterator();
++ * while (it.hasNext()) {
++ *   Object key = it.next();
++ *   Object value = it.getValue();
++ *   it.setValue(newValue);
++ * }
++ * </pre>
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class EntrySetMapIterator <K,V> implements MapIterator<K, V>, ResettableIterator<K> {
++
++    private final Map<K, V> map;
++    private Iterator<Map.Entry<K, V>> iterator;
++    private Map.Entry<K, V> last;
++    private boolean canRemove = false;
++
++    /**
++     * Constructor.
++     *
++     * @param map the map to iterate over
++     */
++    public EntrySetMapIterator(Map<K, V> map) {
++        super();
++        this.map = map;
++        this.iterator = map.entrySet().iterator();
++    }
++
++    //-----------------------------------------------------------------------    
++    /**
++     * Checks to see if there are more entries still to be iterated.
++     *
++     * @return <code>true</code> if the iterator has more elements
++     */
++    public boolean hasNext() {
++        return iterator.hasNext();
++    }
++
++    /**
++     * Gets the next <em>key</em> from the <code>Map</code>.
++     *
++     * @return the next key in the iteration
++     * @throws java.util.NoSuchElementException
++     *          if the iteration is finished
++     */
++    public K next() {
++        last = iterator.next();
++        canRemove = true;
++        return last.getKey();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Removes the last returned key from the underlying <code>Map</code>.
++     * <p/>
++     * This method can be called once per call to <code>next()</code>.
++     *
++     * @throws UnsupportedOperationException if remove is not supported by the map
++     * @throws IllegalStateException         if <code>next()</code> has not yet been called
++     * @throws IllegalStateException         if <code>remove()</code> has already been called
++     *                                       since the last call to <code>next()</code>
++     */
++    public void remove() {
++        if (canRemove == false) {
++            throw new IllegalStateException("Iterator remove() can only be called once after next()");
++        }
++        iterator.remove();
++        last = null;
++        canRemove = false;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the current key, which is the key returned by the last call
++     * to <code>next()</code>.
++     *
++     * @return the current key
++     * @throws IllegalStateException if <code>next()</code> has not yet been called
++     */
++    public K getKey() {
++        if (last == null) {
++            throw new IllegalStateException("Iterator getKey() can only be called after next() and before remove()");
++        }
++        return last.getKey();
++    }
++
++    /**
++     * Gets the current value, which is the value associated with the last key
++     * returned by <code>next()</code>.
++     *
++     * @return the current value
++     * @throws IllegalStateException if <code>next()</code> has not yet been called
++     */
++    public V getValue() {
++        if (last == null) {
++            throw new IllegalStateException("Iterator getValue() can only be called after next() and before remove()");
++        }
++        return last.getValue();
++    }
++
++    /**
++     * Sets the value associated with the current key.
++     *
++     * @param value the new value
++     * @return the previous value
++     * @throws UnsupportedOperationException if setValue is not supported by the map
++     * @throws IllegalStateException         if <code>next()</code> has not yet been called
++     * @throws IllegalStateException         if <code>remove()</code> has been called since the
++     *                                       last call to <code>next()</code>
++     */
++    public V setValue(V value) {
++        if (last == null) {
++            throw new IllegalStateException("Iterator setValue() can only be called after next() and before remove()");
++        }
++        return last.setValue(value);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Resets the state of the iterator.
++     */
++    public void reset() {
++        iterator = map.entrySet().iterator();
++        last = null;
++        canRemove = false;
++    }
++
++    /**
++     * Gets the iterator as a String.
++     *
++     * @return a string version of the iterator
++     */
++    public String toString() {
++        if (last != null) {
++            return "MapIterator[" + getKey() + "=" + getValue() + "]";
++        } else {
++            return "MapIterator[]";
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/EnumerationIterator.java
+@@ -0,0 +1,146 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import java.util.Collection;
++import java.util.Enumeration;
++import java.util.Iterator;
++
++/**
++ * Adapter to make {@link Enumeration Enumeration} instances appear
++ * to be {@link Iterator Iterator} instances.
++ *
++ * @author <a href="mailto:jstrachan at apache.org">James Strachan</a>
++ * @author Matt Hall, John Watkinson, <a href="mailto:dlr at finemaltcoding.com">Daniel Rall</a>
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 1.0
++ */
++public class EnumerationIterator <E> implements Iterator<E> {
++
++    /**
++     * The collection to remove elements from
++     */
++    private Collection<E> collection;
++    /**
++     * The enumeration being converted
++     */
++    private Enumeration<E> enumeration;
++    /**
++     * The last object retrieved
++     */
++    private E last;
++    
++    // Constructors
++    //-----------------------------------------------------------------------
++    /**
++     * Constructs a new <code>EnumerationIterator</code> that will not
++     * function until {@link #setEnumeration(Enumeration)} is called.
++     */
++    public EnumerationIterator() {
++        this(null, null);
++    }
++
++    /**
++     * Constructs a new <code>EnumerationIterator</code> that provides
++     * an iterator view of the given enumeration.
++     *
++     * @param enumeration the enumeration to use
++     */
++    public EnumerationIterator(final Enumeration<E> enumeration) {
++        this(enumeration, null);
++    }
++
++    /**
++     * Constructs a new <code>EnumerationIterator</code> that will remove
++     * elements from the specified collection.
++     *
++     * @param enumeration the enumeration to use
++     * @param collection  the collection to remove elements form
++     */
++    public EnumerationIterator(final Enumeration<E> enumeration, final Collection<E> collection) {
++        super();
++        this.enumeration = enumeration;
++        this.collection = collection;
++        this.last = null;
++    }
++
++    // Iterator interface
++    //-----------------------------------------------------------------------
++    /**
++     * Returns true if the underlying enumeration has more elements.
++     *
++     * @return true if the underlying enumeration has more elements
++     * @throws NullPointerException if the underlying enumeration is null
++     */
++    public boolean hasNext() {
++        return enumeration.hasMoreElements();
++    }
++
++    /**
++     * Returns the next object from the enumeration.
++     *
++     * @return the next object from the enumeration
++     * @throws NullPointerException if the enumeration is null
++     */
++    public E next() {
++        last = enumeration.nextElement();
++        return last;
++    }
++
++    /**
++     * Removes the last retrieved element if a collection is attached.
++     * <p/>
++     * Functions if an associated <code>Collection</code> is known.
++     * If so, the first occurrence of the last returned object from this
++     * iterator will be removed from the collection.
++     *
++     * @throws IllegalStateException         <code>next()</code> not called.
++     * @throws UnsupportedOperationException if no associated collection
++     */
++    public void remove() {
++        if (collection != null) {
++            if (last != null) {
++                collection.remove(last);
++            } else {
++                throw new IllegalStateException("next() must have been called for remove() to function");
++            }
++        } else {
++            throw new UnsupportedOperationException("No Collection associated with this Iterator");
++        }
++    }
++
++    // Properties
++    //-----------------------------------------------------------------------
++    /**
++     * Returns the underlying enumeration.
++     *
++     * @return the underlying enumeration
++     */
++    public Enumeration<E> getEnumeration() {
++        return enumeration;
++    }
++
++    /**
++     * Sets the underlying enumeration.
++     *
++     * @param enumeration the new underlying enumeration
++     */
++    public void setEnumeration(final Enumeration<E> enumeration) {
++        this.enumeration = enumeration;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/FilterIterator.java
+@@ -0,0 +1,192 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.util.Iterator;
++import java.util.NoSuchElementException;
++
++/**
++ * Decorates an iterator such that only elements matching a predicate filter
++ * are returned.
++ *
++ * @author James Strachan
++ * @author Jan Sorensen
++ * @author Ralph Wagner
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 1.0
++ */
++public class FilterIterator <E> implements Iterator<E> {
++
++    /**
++     * The iterator being used
++     */
++    private Iterator<E> iterator;
++    /**
++     * The predicate being used
++     */
++    private Predicate<? super E> predicate;
++    /**
++     * The next object in the iteration
++     */
++    private E nextObject;
++    /**
++     * Whether the next object has been calculated yet
++     */
++    private boolean nextObjectSet = false;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructs a new <code>FilterIterator</code> that will not function
++     * until {@link #setIterator(Iterator) setIterator} is invoked.
++     */
++    public FilterIterator() {
++        super();
++    }
++
++    /**
++     * Constructs a new <code>FilterIterator</code> that will not function
++     * until {@link #setPredicate(Predicate) setPredicate} is invoked.
++     *
++     * @param iterator the iterator to use
++     */
++    public FilterIterator(Iterator<E> iterator) {
++        super();
++        this.iterator = iterator;
++    }
++
++    /**
++     * Constructs a new <code>FilterIterator</code> that will use the
++     * given iterator and predicate.
++     *
++     * @param iterator  the iterator to use
++     * @param predicate the predicate to use
++     */
++    public FilterIterator(Iterator<E> iterator, Predicate<? super E> predicate) {
++        super();
++        this.iterator = iterator;
++        this.predicate = predicate;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns true if the underlying iterator contains an object that
++     * matches the predicate.
++     *
++     * @return true if there is another object that matches the predicate
++     */
++    public boolean hasNext() {
++        if (nextObjectSet) {
++            return true;
++        } else {
++            return setNextObject();
++        }
++    }
++
++    /**
++     * Returns the next object that matches the predicate.
++     *
++     * @return the next object which matches the given predicate
++     * @throws NoSuchElementException if there are no more elements that
++     *                                match the predicate
++     */
++    public E next() {
++        if (!nextObjectSet) {
++            if (!setNextObject()) {
++                throw new NoSuchElementException();
++            }
++        }
++        nextObjectSet = false;
++        return nextObject;
++    }
++
++    /**
++     * Removes from the underlying collection of the base iterator the last
++     * element returned by this iterator.
++     * This method can only be called
++     * if <code>next()</code> was called, but not after
++     * <code>hasNext()</code>, because the <code>hasNext()</code> call
++     * changes the base iterator.
++     *
++     * @throws IllegalStateException if <code>hasNext()</code> has already
++     *                               been called.
++     */
++    public void remove() {
++        if (nextObjectSet) {
++            throw new IllegalStateException("remove() cannot be called");
++        }
++        iterator.remove();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the iterator this iterator is using.
++     *
++     * @return the iterator.
++     */
++    public Iterator<E> getIterator() {
++        return iterator;
++    }
++
++    /**
++     * Sets the iterator for this iterator to use.
++     * If iteration has started, this effectively resets the iterator.
++     *
++     * @param iterator the iterator to use
++     */
++    public void setIterator(Iterator<E> iterator) {
++        this.iterator = iterator;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the predicate this iterator is using.
++     *
++     * @return the predicate.
++     */
++    public Predicate<? super E> getPredicate() {
++        return predicate;
++    }
++
++    /**
++     * Sets the predicate this the iterator to use.
++     *
++     * @param predicate the transformer to use
++     */
++    public void setPredicate(Predicate<? super E> predicate) {
++        this.predicate = predicate;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Set nextObject to the next object. If there are no more
++     * objects then return false. Otherwise, return true.
++     */
++    private boolean setNextObject() {
++        while (iterator.hasNext()) {
++            E object = iterator.next();
++            if (predicate.evaluate(object)) {
++                nextObject = object;
++                nextObjectSet = true;
++                return true;
++            }
++        }
++        return false;
++    }
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/FilterListIterator.java
+@@ -0,0 +1,290 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.util.ListIterator;
++import java.util.NoSuchElementException;
++
++/**
++ * A proxy {@link ListIterator ListIterator} which
++ * takes a {@link Predicate Predicate} instance to filter
++ * out objects from an underlying <code>ListIterator</code>
++ * instance. Only objects for which the specified
++ * <code>Predicate</code> evaluates to <code>true</code> are
++ * returned by the iterator.
++ *
++ * @author Matt Hall, John Watkinson, Rodney Waldhoff
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 2.0
++ */
++public class FilterListIterator <E> implements ListIterator<E> {
++
++    /**
++     * The iterator being used
++     */
++    private ListIterator<E> iterator;
++
++    /**
++     * The predicate being used
++     */
++    private Predicate<? super E> predicate;
++
++    /**
++     * The value of the next (matching) object, when
++     * {@link #nextObjectSet} is true.
++     */
++    private E nextObject;
++
++    /**
++     * Whether or not the {@link #nextObject} has been set
++     * (possibly to <code>null</code>).
++     */
++    private boolean nextObjectSet = false;
++
++    /**
++     * The value of the previous (matching) object, when
++     * {@link #previousObjectSet} is true.
++     */
++    private E previousObject;
++
++    /**
++     * Whether or not the {@link #previousObject} has been set
++     * (possibly to <code>null</code>).
++     */
++    private boolean previousObjectSet = false;
++
++    /**
++     * The index of the element that would be returned by {@link #next}.
++     */
++    private int nextIndex = 0;
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructs a new <code>FilterListIterator</code> that will not
++     * function until
++     * {@link #setPredicate(Predicate) setPredicate} is invoked.
++     */
++    public FilterListIterator() {
++        super();
++    }
++
++    /**
++     * Constructs a new <code>FilterListIterator</code> that will not
++     * function until {@link #setPredicate(Predicate) setPredicate} is invoked.
++     *
++     * @param iterator the iterator to use
++     */
++    public FilterListIterator(ListIterator<E> iterator) {
++        super();
++        this.iterator = iterator;
++    }
++
++    /**
++     * Constructs a new <code>FilterListIterator</code>.
++     *
++     * @param iterator  the iterator to use
++     * @param predicate the predicate to use
++     */
++    public FilterListIterator(ListIterator<E> iterator, Predicate<? super E> predicate) {
++        super();
++        this.iterator = iterator;
++        this.predicate = predicate;
++    }
++
++    /**
++     * Constructs a new <code>FilterListIterator</code>.
++     *
++     * @param predicate the predicate to use.
++     */
++    public FilterListIterator(Predicate<? super E> predicate) {
++        super();
++        this.predicate = predicate;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Not supported.
++     */
++    public void add(E o) {
++        throw new UnsupportedOperationException("FilterListIterator.add(Object) is not supported.");
++    }
++
++    public boolean hasNext() {
++        if (nextObjectSet) {
++            return true;
++        } else {
++            return setNextObject();
++        }
++    }
++
++    public boolean hasPrevious() {
++        if (previousObjectSet) {
++            return true;
++        } else {
++            return setPreviousObject();
++        }
++    }
++
++    public E next() {
++        if (!nextObjectSet) {
++            if (!setNextObject()) {
++                throw new NoSuchElementException();
++            }
++        }
++        nextIndex++;
++        E temp = nextObject;
++        clearNextObject();
++        return temp;
++    }
++
++    public int nextIndex() {
++        return nextIndex;
++    }
++
++    public E previous() {
++        if (!previousObjectSet) {
++            if (!setPreviousObject()) {
++                throw new NoSuchElementException();
++            }
++        }
++        nextIndex--;
++        E temp = previousObject;
++        clearPreviousObject();
++        return temp;
++    }
++
++    public int previousIndex() {
++        return (nextIndex - 1);
++    }
++
++    /**
++     * Not supported.
++     */
++    public void remove() {
++        throw new UnsupportedOperationException("FilterListIterator.remove() is not supported.");
++    }
++
++    /**
++     * Not supported.
++     */
++    public void set(E o) {
++        throw new UnsupportedOperationException("FilterListIterator.set(Object) is not supported.");
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the iterator this iterator is using.
++     *
++     * @return the iterator.
++     */
++    public ListIterator<E> getListIterator() {
++        return iterator;
++    }
++
++    /**
++     * Sets the iterator for this iterator to use.
++     * If iteration has started, this effectively resets the iterator.
++     *
++     * @param iterator the iterator to use
++     */
++    public void setListIterator(ListIterator<E> iterator) {
++        this.iterator = iterator;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the predicate this iterator is using.
++     *
++     * @return the predicate.
++     */
++    public Predicate<? super E> getPredicate() {
++        return predicate;
++    }
++
++    /**
++     * Sets the predicate this the iterator to use.
++     *
++     * @param predicate the transformer to use
++     */
++    public void setPredicate(Predicate<? super E> predicate) {
++        this.predicate = predicate;
++    }
++
++    //-----------------------------------------------------------------------
++    private void clearNextObject() {
++        nextObject = null;
++        nextObjectSet = false;
++    }
++
++    private boolean setNextObject() {
++        // if previousObjectSet,
++        // then we've walked back one step in the 
++        // underlying list (due to a hasPrevious() call)
++        // so skip ahead one matching object
++        if (previousObjectSet) {
++            clearPreviousObject();
++            if (!setNextObject()) {
++                return false;
++            } else {
++                clearNextObject();
++            }
++        }
++
++        while (iterator.hasNext()) {
++            E object = iterator.next();
++            if (predicate.evaluate(object)) {
++                nextObject = object;
++                nextObjectSet = true;
++                return true;
++            }
++        }
++        return false;
++    }
++
++    private void clearPreviousObject() {
++        previousObject = null;
++        previousObjectSet = false;
++    }
++
++    private boolean setPreviousObject() {
++        // if nextObjectSet,
++        // then we've walked back one step in the 
++        // underlying list (due to a hasNext() call)
++        // so skip ahead one matching object
++        if (nextObjectSet) {
++            clearNextObject();
++            if (!setPreviousObject()) {
++                return false;
++            } else {
++                clearPreviousObject();
++            }
++        }
++
++        while (iterator.hasPrevious()) {
++            E object = iterator.previous();
++            if (predicate.evaluate(object)) {
++                previousObject = object;
++                previousObjectSet = true;
++                return true;
++            }
++        }
++        return false;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/IteratorChain.java
+@@ -0,0 +1,293 @@
++// GenericsNote: Converted.
++// GenericsNote: Some questions about things like UnmodifiableList.decorate(iteratorChain); and so on
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.list.UnmodifiableList;
++
++import java.util.ArrayList;
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.List;
++
++/**
++ * An IteratorChain is an Iterator that wraps a number of Iterators.
++ * <p/>
++ * This class makes multiple iterators look like one to the caller
++ * When any method from the Iterator interface is called, the IteratorChain
++ * will delegate to a single underlying Iterator. The IteratorChain will
++ * invoke the Iterators in sequence until all Iterators are exhausted.
++ * <p/>
++ * Under many circumstances, linking Iterators together in this manner is
++ * more efficient (and convenient) than reading out the contents of each
++ * Iterator into a List and creating a new Iterator.
++ * <p/>
++ * Calling a method that adds new Iterator<i>after a method in the Iterator
++ * interface has been called</i> will result in an UnsupportedOperationException.
++ * Subclasses should <i>take care</i> to not alter the underlying List of Iterators.
++ * <p/>
++ * NOTE: As from version 3.0, the IteratorChain may contain no
++ * iterators. In this case the class will function as an empty iterator.
++ *
++ * @author Morgan Delagrange
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 2.1
++ */
++public class IteratorChain <E> implements Iterator<E> {
++
++    /**
++     * The chain of iterators
++     */
++    protected final List<Iterator<? extends E>> iteratorChain = new ArrayList<Iterator<? extends E>>();
++    /**
++     * The index of the current iterator
++     */
++    protected int currentIteratorIndex = 0;
++    /**
++     * The current iterator
++     */
++    protected Iterator<? extends E> currentIterator = null;
++    /**
++     * The "last used" Iterator is the Iterator upon which
++     * next() or hasNext() was most recently called
++     * used for the remove() operation only
++     */
++    protected Iterator<? extends E> lastUsedIterator = null;
++    /**
++     * ComparatorChain is "locked" after the first time
++     * compare(Object,Object) is called
++     */
++    protected boolean isLocked = false;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Construct an IteratorChain with no Iterators.
++     * <p/>
++     * You will normally use {@link #addIterator(Iterator)} to add
++     * some iterators after using this constructor.
++     */
++    public IteratorChain() {
++        super();
++    }
++
++    /**
++     * Construct an IteratorChain with a single Iterator.
++     *
++     * @param iterator first Iterator in the IteratorChain
++     * @throws NullPointerException if the iterator is null
++     */
++    public IteratorChain(Iterator<? extends E> iterator) {
++        super();
++        addIterator(iterator);
++    }
++
++    /**
++     * Constructs a new <code>IteratorChain</code> over the two
++     * given iterators.
++     *
++     * @param a the first child iterator
++     * @param b the second child iterator
++     * @throws NullPointerException if either iterator is null
++     */
++    public IteratorChain(Iterator<? extends E> a, Iterator<? extends E> b) {
++        super();
++        addIterator(a);
++        addIterator(b);
++    }
++
++    /**
++     * Constructs a new <code>IteratorChain</code> over the array
++     * of iterators.
++     *
++     * @param iterators the array of iterators
++     * @throws NullPointerException if iterators array is or contains null
++     */
++    public IteratorChain(Iterator<? extends E>[] iterators) {
++        super();
++        for (int i = 0; i < iterators.length; i++) {
++            addIterator(iterators[i]);
++        }
++    }
++
++    /**
++     * Constructs a new <code>IteratorChain</code> over the collection
++     * of iterators.
++     *
++     * @param iterators the collection of iterators
++     * @throws NullPointerException if iterators collection is or contains null
++     * @throws ClassCastException   if iterators collection doesn't contain an iterator
++     */
++    public IteratorChain(Collection<Iterator<? extends E>> iterators) {
++        super();
++        for (Iterator<? extends E> iterator : iterators) {
++            addIterator(iterator);
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Add an Iterator to the end of the chain
++     *
++     * @param iterator Iterator to add
++     * @throws IllegalStateException if I've already started iterating
++     * @throws NullPointerException  if the iterator is null
++     */
++    public void addIterator(Iterator<? extends E> iterator) {
++        checkLocked();
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        iteratorChain.add(iterator);
++    }
++
++    /**
++     * Set the Iterator at the given index
++     *
++     * @param index    index of the Iterator to replace
++     * @param iterator Iterator to place at the given index
++     * @throws IndexOutOfBoundsException if index < 0 or index > size()
++     * @throws IllegalStateException     if I've already started iterating
++     * @throws NullPointerException      if the iterator is null
++     */
++    public void setIterator(int index, Iterator<? extends E> iterator) throws IndexOutOfBoundsException {
++        checkLocked();
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        iteratorChain.set(index, iterator);
++    }
++
++    /**
++     * Get the list of Iterators (unmodifiable)
++     *
++     * @return the unmodifiable list of iterators added
++     */
++    public List<Iterator<? extends E>> getIterators() {
++        return UnmodifiableList.decorate(iteratorChain);
++    }
++
++    /**
++     * Number of Iterators in the current IteratorChain.
++     *
++     * @return Iterator count
++     */
++    public int size() {
++        return iteratorChain.size();
++    }
++
++    /**
++     * Determine if modifications can still be made to the IteratorChain.
++     * IteratorChains cannot be modified once they have executed a method
++     * from the Iterator interface.
++     *
++     * @return true if IteratorChain cannot be modified, false if it can
++     */
++    public boolean isLocked() {
++        return isLocked;
++    }
++
++    /**
++     * Checks whether the iterator chain is now locked and in use.
++     */
++    private void checkLocked() {
++        if (isLocked == true) {
++            throw new UnsupportedOperationException("IteratorChain cannot be changed after the first use of a method from the Iterator interface");
++        }
++    }
++
++    /**
++     * Lock the chain so no more iterators can be added.
++     * This must be called from all Iterator interface methods.
++     */
++    private void lockChain() {
++        if (isLocked == false) {
++            isLocked = true;
++        }
++    }
++
++    /**
++     * Updates the current iterator field to ensure that the current Iterator
++     * is not exhausted
++     */
++    protected void updateCurrentIterator() {
++        if (currentIterator == null) {
++            if (iteratorChain.isEmpty()) {
++                currentIterator = EmptyIterator.INSTANCE;
++            } else {
++                currentIterator = iteratorChain.get(0);
++            }
++            // set last used iterator here, in case the user calls remove
++            // before calling hasNext() or next() (although they shouldn't)
++            lastUsedIterator = currentIterator;
++        }
++
++        while (currentIterator.hasNext() == false && currentIteratorIndex < iteratorChain.size() - 1) {
++            currentIteratorIndex++;
++            currentIterator = iteratorChain.get(currentIteratorIndex);
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Return true if any Iterator in the IteratorChain has a remaining element.
++     *
++     * @return true if elements remain
++     */
++    public boolean hasNext() {
++        lockChain();
++        updateCurrentIterator();
++        lastUsedIterator = currentIterator;
++
++        return currentIterator.hasNext();
++    }
++
++    /**
++     * Returns the next Object of the current Iterator
++     *
++     * @return Object from the current Iterator
++     * @throws java.util.NoSuchElementException
++     *          if all the Iterators are exhausted
++     */
++    public E next() {
++        lockChain();
++        updateCurrentIterator();
++        lastUsedIterator = currentIterator;
++
++        return currentIterator.next();
++    }
++
++    /**
++     * Removes from the underlying collection the last element
++     * returned by the Iterator.  As with next() and hasNext(),
++     * this method calls remove() on the underlying Iterator.
++     * Therefore, this method may throw an
++     * UnsupportedOperationException if the underlying
++     * Iterator does not support this method.
++     *
++     * @throws UnsupportedOperationException if the remove operator is not supported by the underlying Iterator
++     * @throws IllegalStateException         if the next method has not yet been called, or the remove method has
++     *                                       already been called after the last call to the next method.
++     */
++    public void remove() {
++        lockChain();
++        updateCurrentIterator();
++
++        lastUsedIterator.remove();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/IteratorEnumeration.java
+@@ -0,0 +1,102 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import java.util.Enumeration;
++import java.util.Iterator;
++
++/**
++ * Adapter to make an {@link Iterator Iterator} instance appear to be
++ * an {@link Enumeration Enumeration} instance.
++ *
++ * @author Matt Hall, John Watkinson, <a href="mailto:jstrachan at apache.org">James Strachan</a>
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 1.0
++ */
++public class IteratorEnumeration <E> implements Enumeration<E> {
++
++    /**
++     * The iterator being decorated.
++     */
++    private Iterator<E> iterator;
++
++    /**
++     * Constructs a new <code>IteratorEnumeration</code> that will not
++     * function until {@link #setIterator(Iterator) setIterator} is
++     * invoked.
++     */
++    public IteratorEnumeration() {
++        super();
++    }
++
++    /**
++     * Constructs a new <code>IteratorEnumeration</code> that will use
++     * the given iterator.
++     *
++     * @param iterator the iterator to use
++     */
++    public IteratorEnumeration(Iterator<E> iterator) {
++        super();
++        this.iterator = iterator;
++    }
++
++    // Iterator interface
++    //-------------------------------------------------------------------------
++
++    /**
++     * Returns true if the underlying iterator has more elements.
++     *
++     * @return true if the underlying iterator has more elements
++     */
++    public boolean hasMoreElements() {
++        return iterator.hasNext();
++    }
++
++    /**
++     * Returns the next element from the underlying iterator.
++     *
++     * @return the next element from the underlying iterator.
++     * @throws java.util.NoSuchElementException
++     *          if the underlying iterator has no
++     *          more elements
++     */
++    public E nextElement() {
++        return iterator.next();
++    }
++
++    // Properties
++    //-------------------------------------------------------------------------
++
++    /**
++     * Returns the underlying iterator.
++     *
++     * @return the underlying iterator
++     */
++    public Iterator<E> getIterator() {
++        return iterator;
++    }
++
++    /**
++     * Sets the underlying iterator.
++     *
++     * @param iterator the new underlying iterator
++     */
++    public void setIterator(Iterator<E> iterator) {
++        this.iterator = iterator;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/ListIteratorWrapper.java
+@@ -0,0 +1,180 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import java.util.Iterator;
++import java.util.LinkedList;
++import java.util.ListIterator;
++import java.util.NoSuchElementException;
++
++/**
++ * As the wrapped Iterator is traversed, ListIteratorWrapper
++ * builds a LinkedList of its values, permitting all required
++ * operations of ListIterator.
++ *
++ * @author Morgan Delagrange
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 2.1
++ */
++public class ListIteratorWrapper <E> implements ListIterator<E> {
++
++    /**
++     * Holds value of property "iterator"
++     */
++    private final Iterator<E> iterator;
++    private final LinkedList<E> list = new LinkedList<E>();
++
++    // position of this iterator
++    private int currentIndex = 0;
++    // position of the wrapped iterator
++    // this Iterator should only be used to populate the list
++    private int wrappedIteratorIndex = 0;
++
++    private static final String UNSUPPORTED_OPERATION_MESSAGE = "ListIteratorWrapper does not support optional operations of ListIterator.";
++
++    // Constructor
++    //-------------------------------------------------------------------------
++
++    /**
++     * Constructs a new <code>ListIteratorWrapper</code> that will wrap
++     * the given iterator.
++     *
++     * @param iterator the iterator to wrap
++     * @throws NullPointerException if the iterator is null
++     */
++    public ListIteratorWrapper(Iterator<E> iterator) {
++        super();
++        if (iterator == null) {
++            throw new NullPointerException("Iterator must not be null");
++        }
++        this.iterator = iterator;
++    }
++
++    // ListIterator interface
++    //-------------------------------------------------------------------------
++
++    /**
++     * Throws {@link UnsupportedOperationException}.
++     *
++     * @param o ignored
++     * @throws UnsupportedOperationException always
++     */
++    public void add(E o) throws UnsupportedOperationException {
++        throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_MESSAGE);
++    }
++
++
++    /**
++     * Returns true if there are more elements in the iterator.
++     *
++     * @return true if there are more elements
++     */
++    public boolean hasNext() {
++        if (currentIndex == wrappedIteratorIndex) {
++            return iterator.hasNext();
++        }
++
++        return true;
++    }
++
++    /**
++     * Returns true if there are previous elements in the iterator.
++     *
++     * @return true if there are previous elements
++     */
++    public boolean hasPrevious() {
++        if (currentIndex == 0) {
++            return false;
++        }
++
++        return true;
++    }
++
++    /**
++     * Returns the next element from the iterator.
++     *
++     * @return the next element from the iterator
++     * @throws NoSuchElementException if there are no more elements
++     */
++    public E next() throws NoSuchElementException {
++        if (currentIndex < wrappedIteratorIndex) {
++            ++currentIndex;
++            return list.get(currentIndex - 1);
++        }
++
++        E retval = iterator.next();
++        list.add(retval);
++        ++currentIndex;
++        ++wrappedIteratorIndex;
++        return retval;
++    }
++
++    /**
++     * Returns in the index of the next element.
++     *
++     * @return the index of the next element
++     */
++    public int nextIndex() {
++        return currentIndex;
++    }
++
++    /**
++     * Returns the the previous element.
++     *
++     * @return the previous element
++     * @throws NoSuchElementException if there are no previous elements
++     */
++    public E previous() throws NoSuchElementException {
++        if (currentIndex == 0) {
++            throw new NoSuchElementException();
++        }
++
++        --currentIndex;
++        return list.get(currentIndex);
++    }
++
++    /**
++     * Returns the index of the previous element.
++     *
++     * @return the index of the previous element
++     */
++    public int previousIndex() {
++        return currentIndex - 1;
++    }
++
++    /**
++     * Throws {@link UnsupportedOperationException}.
++     *
++     * @throws UnsupportedOperationException always
++     */
++    public void remove() throws UnsupportedOperationException {
++        throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_MESSAGE);
++    }
++
++    /**
++     * Throws {@link UnsupportedOperationException}.
++     *
++     * @param o ignored
++     * @throws UnsupportedOperationException always
++     */
++    public void set(E o) throws UnsupportedOperationException {
++        throw new UnsupportedOperationException(UNSUPPORTED_OPERATION_MESSAGE);
++    }
++
++}
++
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/LoopingIterator.java
+@@ -0,0 +1,130 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.ResettableIterator;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.NoSuchElementException;
++
++/**
++ * An Iterator that restarts when it reaches the end.
++ * <p/>
++ * The iterator will loop continuously around the provided elements, unless
++ * there are no elements in the collection to begin with, or all the elements
++ * have been {@link #remove removed}.
++ * <p/>
++ * Concurrent modifications are not directly supported, and for most collection
++ * implementations will throw a ConcurrentModificationException.
++ *
++ * @author <a href="mailto:joncrlsn at users.sf.net">Jonathan Carlson</a>
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class LoopingIterator <E> implements ResettableIterator<E> {
++
++    /**
++     * The collection to base the iterator on
++     */
++    private Collection<E> collection;
++    /**
++     * The current iterator
++     */
++    private Iterator<E> iterator;
++
++    /**
++     * Constructor that wraps a collection.
++     * <p/>
++     * There is no way to reset an Iterator instance without recreating it from
++     * the original source, so the Collection must be passed in.
++     *
++     * @param coll the collection to wrap
++     * @throws NullPointerException if the collection is null
++     */
++    public LoopingIterator(Collection<E> coll) {
++        if (coll == null) {
++            throw new NullPointerException("The collection must not be null");
++        }
++        collection = coll;
++        reset();
++    }
++
++    /**
++     * Has the iterator any more elements.
++     * <p/>
++     * Returns false only if the collection originally had zero elements, or
++     * all the elements have been {@link #remove removed}.
++     *
++     * @return <code>true</code> if there are more elements
++     */
++    public boolean hasNext() {
++        return (collection.size() > 0);
++    }
++
++    /**
++     * Returns the next object in the collection.
++     * <p/>
++     * If at the end of the collection, return the first element.
++     *
++     * @throws NoSuchElementException if there are no elements
++     *                                at all.  Use {@link #hasNext} to avoid this error.
++     */
++    public E next() {
++        if (collection.size() == 0) {
++            throw new NoSuchElementException("There are no elements for this iterator to loop on");
++        }
++        if (iterator.hasNext() == false) {
++            reset();
++        }
++        return iterator.next();
++    }
++
++    /**
++     * Removes the previously retrieved item from the underlying collection.
++     * <p/>
++     * This feature is only supported if the underlying collection's
++     * {@link Collection#iterator iterator} method returns an implementation
++     * that supports it.
++     * <p/>
++     * This method can only be called after at least one {@link #next} method call.
++     * After a removal, the remove method may not be called again until another
++     * next has been performed. If the {@link #reset} is called, then remove may
++     * not be called until {@link #next} is called again.
++     */
++    public void remove() {
++        iterator.remove();
++    }
++
++    /**
++     * Resets the iterator back to the start of the collection.
++     */
++    public void reset() {
++        iterator = collection.iterator();
++    }
++
++    /**
++     * Gets the size of the collection underlying the iterator.
++     *
++     * @return the current collection size
++     */
++    public int size() {
++        return collection.size();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/ObjectArrayIterator.java
+@@ -0,0 +1,222 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.ResettableIterator;
++
++import java.util.Iterator;
++import java.util.NoSuchElementException;
++
++/**
++ * An {@link Iterator} over an array of objects.
++ * <p/>
++ * This iterator does not support {@link #remove}, as the object array cannot be
++ * structurally modified.
++ * <p/>
++ * The iterator implements a {@link #reset} method, allowing the reset of the iterator
++ * back to the start if required.
++ *
++ * @author James Strachan
++ * @author Mauricio S. Moura
++ * @author Michael A. Smith
++ * @author Neil O'Toole
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Phil Steitz
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public class ObjectArrayIterator <E> implements Iterator<E>, ResettableIterator<E> {
++
++    /**
++     * The array
++     */
++    protected E[] array = null;
++    /**
++     * The start index to loop from
++     */
++    protected int startIndex = 0;
++    /**
++     * The end index to loop to
++     */
++    protected int endIndex = 0;
++    /**
++     * The current iterator index
++     */
++    protected int index = 0;
++
++    /**
++     * Constructor for use with <code>setArray</code>.
++     * <p/>
++     * Using this constructor, the iterator is equivalent to an empty iterator
++     * until {@link #setArray} is  called to establish the array to iterate over.
++     */
++    public ObjectArrayIterator() {
++        super();
++    }
++
++    /**
++     * Constructs an ObjectArrayIterator that will iterate over the values in the
++     * specified array.
++     *
++     * @param array the array to iterate over
++     * @throws NullPointerException if <code>array</code> is <code>null</code>
++     */
++    public ObjectArrayIterator(E[] array) {
++        this(array, 0, array.length);
++    }
++
++    /**
++     * Constructs an ObjectArrayIterator that will iterate over the values in the
++     * specified array from a specific start index.
++     *
++     * @param array the array to iterate over
++     * @param start the index to start iterating at
++     * @throws NullPointerException      if <code>array</code> is <code>null</code>
++     * @throws IndexOutOfBoundsException if the start index is out of bounds
++     */
++    public ObjectArrayIterator(E[] array, int start) {
++        this(array, start, array.length);
++    }
++
++    /**
++     * Construct an ObjectArrayIterator that will iterate over a range of values
++     * in the specified array.
++     *
++     * @param array the array to iterate over
++     * @param start the index to start iterating at
++     * @param end   the index (exclusive) to finish iterating at
++     * @throws IndexOutOfBoundsException if the start or end index is out of bounds
++     * @throws IllegalArgumentException  if end index is before the start
++     * @throws NullPointerException      if <code>array</code> is <code>null</code>
++     */
++    public ObjectArrayIterator(E[] array, int start, int end) {
++        super();
++        if (start < 0) {
++            throw new ArrayIndexOutOfBoundsException("Start index must not be less than zero");
++        }
++        if (end > array.length) {
++            throw new ArrayIndexOutOfBoundsException("End index must not be greater than the array length");
++        }
++        if (start > array.length) {
++            throw new ArrayIndexOutOfBoundsException("Start index must not be greater than the array length");
++        }
++        if (end < start) {
++            throw new IllegalArgumentException("End index must not be less than start index");
++        }
++        this.array = array;
++        this.startIndex = start;
++        this.endIndex = end;
++        this.index = start;
++    }
++
++    // Iterator interface
++    //-------------------------------------------------------------------------
++
++    /**
++     * Returns true if there are more elements to return from the array.
++     *
++     * @return true if there is a next element to return
++     */
++    public boolean hasNext() {
++        return (this.index < this.endIndex);
++    }
++
++    /**
++     * Returns the next element in the array.
++     *
++     * @return the next element in the array
++     * @throws NoSuchElementException if all the elements in the array
++     *                                have already been returned
++     */
++    public E next() {
++        if (hasNext() == false) {
++            throw new NoSuchElementException();
++        }
++        return this.array[this.index++];
++    }
++
++    /**
++     * Throws {@link UnsupportedOperationException}.
++     *
++     * @throws UnsupportedOperationException always
++     */
++    public void remove() {
++        throw new UnsupportedOperationException("remove() method is not supported for an ObjectArrayIterator");
++    }
++
++    // Properties
++    //-------------------------------------------------------------------------
++
++    /**
++     * Gets the array that this iterator is iterating over.
++     *
++     * @return the array this iterator iterates over, or <code>null</code> if
++     *         the no-arg constructor was used and {@link #setArray} has never
++     *         been called with a valid array.
++     */
++    public E[] getArray() {
++        return this.array;
++    }
++
++    /**
++     * Sets the array that the ArrayIterator should iterate over.
++     * <p/>
++     * This method may only be called once, otherwise an IllegalStateException
++     * will occur.
++     * <p/>
++     * The {@link #reset} method can be used to reset the iterator if required.
++     *
++     * @param array the array that the iterator should iterate over
++     * @throws IllegalStateException if the <code>array</code> was set in the constructor
++     * @throws NullPointerException  if <code>array</code> is <code>null</code>
++     */
++    public void setArray(E[] array) {
++        if (this.array != null) {
++            throw new IllegalStateException("The array to iterate over has already been set");
++        }
++        this.array = array;
++        this.startIndex = 0;
++        this.endIndex = array.length;
++        this.index = 0;
++    }
++
++    /**
++     * Gets the start index to loop from.
++     *
++     * @return the start index
++     */
++    public int getStartIndex() {
++        return this.startIndex;
++    }
++
++    /**
++     * Gets the end index to loop to.
++     *
++     * @return the end index
++     */
++    public int getEndIndex() {
++        return this.endIndex;
++    }
++
++    /**
++     * Resets the iterator back to the start index.
++     */
++    public void reset() {
++        this.index = this.startIndex;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/ObjectArrayListIterator.java
+@@ -0,0 +1,203 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.ResettableListIterator;
++
++import java.util.ListIterator;
++import java.util.NoSuchElementException;
++
++/**
++ * Implements a {@link ListIterator} over an array of objects.
++ * <p/>
++ * This iterator does not support {@link #add} or {@link #remove}, as the object array
++ * cannot be structurally modified. The {@link #set} method is supported however.
++ * <p/>
++ * The iterator implements a {@link #reset} method, allowing the reset of the iterator
++ * back to the start if required.
++ *
++ * @author Neil O'Toole
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Phil Steitz
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @see org.apache.commons.collections15.iterators.ObjectArrayIterator
++ * @see java.util.Iterator
++ * @see java.util.ListIterator
++ * @since Commons Collections 3.0
++ */
++public class ObjectArrayListIterator <E> extends ObjectArrayIterator<E> implements ListIterator<E>, ResettableListIterator<E> {
++
++    /**
++     * Holds the index of the last item returned by a call to <code>next()</code>
++     * or <code>previous()</code>. This is set to <code>-1</code> if neither method
++     * has yet been invoked. <code>lastItemIndex</code> is used to to implement the
++     * {@link #set} method.
++     */
++    protected int lastItemIndex = -1;
++
++    /**
++     * Constructor for use with <code>setArray</code>.
++     * <p/>
++     * Using this constructor, the iterator is equivalent to an empty iterator
++     * until {@link #setArray} is  called to establish the array to iterate over.
++     */
++    public ObjectArrayListIterator() {
++        super();
++    }
++
++    /**
++     * Constructs an ObjectArrayListIterator that will iterate over the values in the
++     * specified array.
++     *
++     * @param array the array to iterate over
++     * @throws NullPointerException if <code>array</code> is <code>null</code>
++     */
++    public ObjectArrayListIterator(E[] array) {
++        super(array);
++    }
++
++    /**
++     * Constructs an ObjectArrayListIterator that will iterate over the values in the
++     * specified array from a specific start index.
++     *
++     * @param array the array to iterate over
++     * @param start the index to start iterating at
++     * @throws NullPointerException      if <code>array</code> is <code>null</code>
++     * @throws IndexOutOfBoundsException if the start index is out of bounds
++     */
++    public ObjectArrayListIterator(E[] array, int start) {
++        super(array, start);
++    }
++
++    /**
++     * Construct an ObjectArrayListIterator that will iterate over a range of values
++     * in the specified array.
++     *
++     * @param array the array to iterate over
++     * @param start the index to start iterating at
++     * @param end   the index (exclusive) to finish iterating at
++     * @throws IndexOutOfBoundsException if the start or end index is out of bounds
++     * @throws IllegalArgumentException  if end index is before the start
++     * @throws NullPointerException      if <code>array</code> is <code>null</code>
++     */
++    public ObjectArrayListIterator(E[] array, int start, int end) {
++        super(array, start, end);
++    }
++
++    // ListIterator interface
++    //-------------------------------------------------------------------------
++
++    /**
++     * Returns true if there are previous elements to return from the array.
++     *
++     * @return true if there is a previous element to return
++     */
++    public boolean hasPrevious() {
++        return (this.index > this.startIndex);
++    }
++
++    /**
++     * Gets the previous element from the array.
++     *
++     * @return the previous element
++     * @throws NoSuchElementException if there is no previous element
++     */
++    public E previous() {
++        if (hasPrevious() == false) {
++            throw new NoSuchElementException();
++        }
++        this.lastItemIndex = --this.index;
++        return this.array[this.index];
++    }
++
++    /**
++     * Gets the next element from the array.
++     *
++     * @return the next element
++     * @throws NoSuchElementException if there is no next element
++     */
++    public E next() {
++        if (hasNext() == false) {
++            throw new NoSuchElementException();
++        }
++        this.lastItemIndex = this.index;
++        return this.array[this.index++];
++    }
++
++    /**
++     * Gets the next index to be retrieved.
++     *
++     * @return the index of the item to be retrieved next
++     */
++    public int nextIndex() {
++        return this.index - this.startIndex;
++    }
++
++    /**
++     * Gets the index of the item to be retrieved if {@link #previous()} is called.
++     *
++     * @return the index of the item to be retrieved next
++     */
++    public int previousIndex() {
++        return this.index - this.startIndex - 1;
++    }
++
++    /**
++     * This iterator does not support modification of its backing array's size, and so will
++     * always throw an {@link UnsupportedOperationException} when this method is invoked.
++     *
++     * @param obj the object to add
++     * @throws UnsupportedOperationException always thrown.
++     */
++    public void add(E obj) {
++        throw new UnsupportedOperationException("add() method is not supported");
++    }
++
++    /**
++     * Sets the element under the cursor.
++     * <p/>
++     * This method sets the element that was returned by the last call
++     * to {@link #next()} of {@link #previous()}.
++     * <p/>
++     * <b>Note:</b> {@link ListIterator} implementations that support <code>add()</code>
++     * and <code>remove()</code> only allow <code>set()</code> to be called once per call
++     * to <code>next()</code> or <code>previous</code> (see the {@link ListIterator}
++     * javadoc for more details). Since this implementation does not support
++     * <code>add()</code> or <code>remove()</code>, <code>set()</code> may be
++     * called as often as desired.
++     *
++     * @param obj the object to set into the array
++     * @throws IllegalStateException if next() has not yet been called.
++     * @throws ClassCastException    if the object type is unsuitable for the array
++     */
++    public void set(E obj) {
++        if (this.lastItemIndex == -1) {
++            throw new IllegalStateException("must call next() or previous() before a call to set()");
++        }
++
++        this.array[this.lastItemIndex] = obj;
++    }
++
++    /**
++     * Resets the iterator back to the start index.
++     */
++    public void reset() {
++        super.reset();
++        this.lastItemIndex = -1;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/ObjectGraphIterator.java
+@@ -0,0 +1,268 @@
++// GenericsNote: Won't be converted, not type safe.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.ArrayStack;
++import org.apache.commons.collections15.Transformer;
++
++import java.util.Iterator;
++import java.util.NoSuchElementException;
++
++/**
++ * An Iterator that can traverse multiple iterators down an object graph.
++ * <p/>
++ * This iterator can extract multiple objects from a complex tree-like object graph.
++ * The iteration starts from a single root object.
++ * It uses a <code>Transformer</code> to extract the iterators and elements.
++ * Its main benefit is that no intermediate <code>List</code> is created.
++ * <p/>
++ * For example, consider an object graph:
++ * <pre>
++ *                 |- Branch -- Leaf
++ *                 |         \- Leaf
++ *         |- Tree |         /- Leaf
++ *         |       |- Branch -- Leaf
++ *  Forest |                 \- Leaf
++ *         |       |- Branch -- Leaf
++ *         |       |         \- Leaf
++ *         |- Tree |         /- Leaf
++ *                 |- Branch -- Leaf
++ *                 |- Branch -- Leaf</pre>
++ * The following <code>Transformer</code>, used in this class, will extract all
++ * the Leaf objects without creating a combined intermediate list:
++ * <pre>
++ * public Object transform(Object input) {
++ *   if (input instanceof Forest) {
++ *     return ((Forest) input).treeIterator();
++ *   }
++ *   if (input instanceof Tree) {
++ *     return ((Tree) input).branchIterator();
++ *   }
++ *   if (input instanceof Branch) {
++ *     return ((Branch) input).leafIterator();
++ *   }
++ *   if (input instanceof Leaf) {
++ *     return input;
++ *   }
++ *   throw new ClassCastException();
++ * }</pre>
++ * <p/>
++ * Internally, iteration starts from the root object. When next is called,
++ * the transformer is called to examine the object. The transformer will return
++ * either an iterator or an object. If the object is an Iterator, the next element
++ * from that iterator is obtained and the process repeats. If the element is an object
++ * it is returned.
++ * <p/>
++ * Under many circumstances, linking Iterators together in this manner is
++ * more efficient (and convenient) than using nested for loops to extract a list.
++ * <p/>
++ * Note: this class is not type-safe in Java 1.5 (no generics).
++ * <p/>
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.1
++ */
++public class ObjectGraphIterator implements Iterator {
++
++    /**
++     * The stack of iterators
++     */
++    protected final ArrayStack stack = new ArrayStack(8);
++    /**
++     * The root object in the tree
++     */
++    protected Object root;
++    /**
++     * The transformer to use
++     */
++    protected Transformer transformer;
++
++    /**
++     * Whether there is another element in the iteration
++     */
++    protected boolean hasNext = false;
++    /**
++     * The current iterator
++     */
++    protected Iterator currentIterator;
++    /**
++     * The current value
++     */
++    protected Object currentValue;
++    /**
++     * The last used iterator, needed for remove()
++     */
++    protected Iterator lastUsedIterator;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructs an ObjectGraphIterator using a root object and transformer.
++     * <p/>
++     * The root object can be an iterator, in which case it will be immediately
++     * looped around.
++     *
++     * @param root        the root object, null will result in an empty iterator
++     * @param transformer the transformer to use, null will use a no effect transformer
++     */
++    public ObjectGraphIterator(Object root, Transformer transformer) {
++        super();
++        if (root instanceof Iterator) {
++            this.currentIterator = (Iterator) root;
++        } else {
++            this.root = root;
++        }
++        this.transformer = transformer;
++    }
++
++    /**
++     * Constructs a ObjectGraphIterator that will handle an iterator of iterators.
++     * <p/>
++     * This constructor exists for convenience to emphasise that this class can
++     * be used to iterate over nested iterators. That is to say that the iterator
++     * passed in here contains other iterators, which may in turn contain further
++     * iterators.
++     *
++     * @param rootIterator the root iterator, null will result in an empty iterator
++     */
++    public ObjectGraphIterator(Iterator rootIterator) {
++        super();
++        this.currentIterator = rootIterator;
++        this.transformer = null;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Loops around the iterators to find the next value to return.
++     */
++    protected void updateCurrentIterator() {
++        if (hasNext) {
++            return;
++        }
++        if (currentIterator == null) {
++            if (root == null) {
++                // do nothing, hasNext will be false
++            } else {
++                if (transformer == null) {
++                    findNext(root);
++                } else {
++                    findNext(transformer.transform(root));
++                }
++                root = null;
++            }
++        } else {
++            findNextByIterator(currentIterator);
++        }
++    }
++
++    /**
++     * Finds the next object in the iteration given any start object.
++     *
++     * @param value the value to start from
++     */
++    protected void findNext(Object value) {
++        if (value instanceof Iterator) {
++            // need to examine this iterator
++            findNextByIterator((Iterator) value);
++        } else {
++            // next value found
++            currentValue = value;
++            hasNext = true;
++        }
++    }
++
++    /**
++     * Finds the next object in the iteration given an iterator.
++     *
++     * @param iterator the iterator to start from
++     */
++    protected void findNextByIterator(Iterator iterator) {
++        if (iterator != currentIterator) {
++            // recurse a level
++            if (currentIterator != null) {
++                stack.push(currentIterator);
++            }
++            currentIterator = iterator;
++        }
++
++        while (currentIterator.hasNext() && hasNext == false) {
++            Object next = currentIterator.next();
++            if (transformer != null) {
++                next = transformer.transform(next);
++            }
++            findNext(next);
++        }
++        if (hasNext) {
++            // next value found
++        } else if (stack.isEmpty()) {
++            // all iterators exhausted
++        } else {
++            // current iterator exhausted, go up a level
++            currentIterator = (Iterator) stack.pop();
++            findNextByIterator(currentIterator);
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Checks whether there are any more elements in the iteration to obtain.
++     *
++     * @return true if elements remain in the iteration
++     */
++    public boolean hasNext() {
++        updateCurrentIterator();
++        return hasNext;
++    }
++
++    /**
++     * Gets the next element of the iteration.
++     *
++     * @return the next element from the iteration
++     * @throws NoSuchElementException if all the Iterators are exhausted
++     */
++    public Object next() {
++        updateCurrentIterator();
++        if (hasNext == false) {
++            throw new NoSuchElementException("No more elements in the iteration");
++        }
++        lastUsedIterator = currentIterator;
++        Object result = currentValue;
++        currentValue = null;
++        hasNext = false;
++        return result;
++    }
++
++    /**
++     * Removes from the underlying collection the last element returned.
++     * <p/>
++     * This method calls remove() on the underlying Iterator and it may
++     * throw an UnsupportedOperationException if the underlying Iterator
++     * does not support this method.
++     *
++     * @throws UnsupportedOperationException if the remove operator is not supported by the underlying Iterator
++     * @throws IllegalStateException         if the next method has not yet been called, or the remove method has
++     *                                       already been called after the last call to the next method.
++     */
++    public void remove() {
++        if (lastUsedIterator == null) {
++            throw new IllegalStateException("Iterator remove() cannot be called at this time");
++        }
++        lastUsedIterator.remove();
++        lastUsedIterator = null;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/SingletonIterator.java
+@@ -0,0 +1,135 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.ResettableIterator;
++
++import java.util.Iterator;
++import java.util.NoSuchElementException;
++
++/**
++ * <code>SingletonIterator</code> is an {@link Iterator} over a single
++ * object instance.
++ *
++ * @author James Strachan
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Rodney Waldhoff
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 2.0
++ */
++public class SingletonIterator <E> implements Iterator<E>, ResettableIterator<E> {
++
++    /**
++     * Whether remove is allowed
++     */
++    private final boolean removeAllowed;
++    /**
++     * Is the cursor before the first element
++     */
++    private boolean beforeFirst = true;
++    /**
++     * Has the element been removed
++     */
++    private boolean removed = false;
++    /**
++     * The object
++     */
++    private E object;
++
++    /**
++     * Constructs a new <code>SingletonIterator</code> where <code>remove</code>
++     * is a permitted operation.
++     *
++     * @param object the single object to return from the iterator
++     */
++    public SingletonIterator(E object) {
++        this(object, true);
++    }
++
++    /**
++     * Constructs a new <code>SingletonIterator</code> optionally choosing if
++     * <code>remove</code> is a permitted operation.
++     *
++     * @param object        the single object to return from the iterator
++     * @param removeAllowed true if remove is allowed
++     * @since Commons Collections 3.1
++     */
++    public SingletonIterator(E object, boolean removeAllowed) {
++        super();
++        this.object = object;
++        this.removeAllowed = removeAllowed;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Is another object available from the iterator?
++     * <p/>
++     * This returns true if the single object hasn't been returned yet.
++     *
++     * @return true if the single object hasn't been returned yet
++     */
++    public boolean hasNext() {
++        return (beforeFirst && !removed);
++    }
++
++    /**
++     * Get the next object from the iterator.
++     * <p/>
++     * This returns the single object if it hasn't been returned yet.
++     *
++     * @return the single object
++     * @throws NoSuchElementException if the single object has already
++     *                                been returned
++     */
++    public E next() {
++        if (!beforeFirst || removed) {
++            throw new NoSuchElementException();
++        }
++        beforeFirst = false;
++        return object;
++    }
++
++    /**
++     * Remove the object from this iterator.
++     *
++     * @throws IllegalStateException         if the <tt>next</tt> method has not
++     *                                       yet been called, or the <tt>remove</tt> method has already
++     *                                       been called after the last call to the <tt>next</tt>
++     *                                       method.
++     * @throws UnsupportedOperationException if remove is not supported
++     */
++    public void remove() {
++        if (removeAllowed) {
++            if (removed || beforeFirst) {
++                throw new IllegalStateException();
++            } else {
++                object = null;
++                removed = true;
++            }
++        } else {
++            throw new UnsupportedOperationException();
++        }
++    }
++
++    /**
++     * Reset the iterator to the start.
++     */
++    public void reset() {
++        beforeFirst = true;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/SingletonListIterator.java
+@@ -0,0 +1,176 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.ResettableListIterator;
++
++import java.util.ListIterator;
++import java.util.NoSuchElementException;
++
++/**
++ * <code>SingletonIterator</code> is an {@link ListIterator} over a single
++ * object instance.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Rodney Waldhoff
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 2.1
++ */
++public class SingletonListIterator <E> implements ListIterator<E>, ResettableListIterator<E> {
++
++    private boolean beforeFirst = true;
++    private boolean nextCalled = false;
++    private boolean removed = false;
++    private E object;
++
++    /**
++     * Constructs a new <code>SingletonListIterator</code>.
++     *
++     * @param object the single object to return from the iterator
++     */
++    public SingletonListIterator(E object) {
++        super();
++        this.object = object;
++    }
++
++    /**
++     * Is another object available from the iterator?
++     * <p/>
++     * This returns true if the single object hasn't been returned yet.
++     *
++     * @return true if the single object hasn't been returned yet
++     */
++    public boolean hasNext() {
++        return beforeFirst && !removed;
++    }
++
++    /**
++     * Is a previous object available from the iterator?
++     * <p/>
++     * This returns true if the single object has been returned.
++     *
++     * @return true if the single object has been returned
++     */
++    public boolean hasPrevious() {
++        return !beforeFirst && !removed;
++    }
++
++    /**
++     * Returns the index of the element that would be returned by a subsequent
++     * call to <tt>next</tt>.
++     *
++     * @return 0 or 1 depending on current state.
++     */
++    public int nextIndex() {
++        return (beforeFirst ? 0 : 1);
++    }
++
++    /**
++     * Returns the index of the element that would be returned by a subsequent
++     * call to <tt>previous</tt>. A return value of -1 indicates that the iterator is currently at
++     * the start.
++     *
++     * @return 0 or -1 depending on current state.
++     */
++    public int previousIndex() {
++        return (beforeFirst ? -1 : 0);
++    }
++
++    /**
++     * Get the next object from the iterator.
++     * <p/>
++     * This returns the single object if it hasn't been returned yet.
++     *
++     * @return the single object
++     * @throws NoSuchElementException if the single object has already
++     *                                been returned
++     */
++    public E next() {
++        if (!beforeFirst || removed) {
++            throw new NoSuchElementException();
++        }
++        beforeFirst = false;
++        nextCalled = true;
++        return object;
++    }
++
++    /**
++     * Get the previous object from the iterator.
++     * <p/>
++     * This returns the single object if it has been returned.
++     *
++     * @return the single object
++     * @throws NoSuchElementException if the single object has not already
++     *                                been returned
++     */
++    public E previous() {
++        if (beforeFirst || removed) {
++            throw new NoSuchElementException();
++        }
++        beforeFirst = true;
++        return object;
++    }
++
++    /**
++     * Remove the object from this iterator.
++     *
++     * @throws IllegalStateException if the <tt>next</tt> or <tt>previous</tt>
++     *                               method has not yet been called, or the <tt>remove</tt> method
++     *                               has already been called after the last call to <tt>next</tt>
++     *                               or <tt>previous</tt>.
++     */
++    public void remove() {
++        if (!nextCalled || removed) {
++            throw new IllegalStateException();
++        } else {
++            object = null;
++            removed = true;
++        }
++    }
++
++    /**
++     * Add always throws {@link UnsupportedOperationException}.
++     *
++     * @throws UnsupportedOperationException always
++     */
++    public void add(E obj) {
++        throw new UnsupportedOperationException("add() is not supported by this iterator");
++    }
++
++    /**
++     * Set sets the value of the singleton.
++     *
++     * @param obj the object to set
++     * @throws IllegalStateException if <tt>next</tt> has not been called
++     *                               or the object has been removed
++     */
++    public void set(E obj) {
++        if (!nextCalled || removed) {
++            throw new IllegalStateException();
++        }
++        this.object = obj;
++    }
++
++    /**
++     * Reset the iterator back to the start.
++     */
++    public void reset() {
++        beforeFirst = true;
++        nextCalled = false;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/TransformIterator.java
+@@ -0,0 +1,155 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.util.Iterator;
++
++/**
++ * Decorates an iterator such that each element returned is transformed.
++ *
++ * @author James Strachan
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 1.0
++ */
++public class TransformIterator <I,O> implements Iterator<O> {
++
++    /**
++     * The iterator being used
++     */
++    private Iterator<I> iterator;
++    /**
++     * The transformer being used
++     */
++    private Transformer<I, O> transformer;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructs a new <code>TransformIterator</code> that will not function
++     * until the {@link #setIterator(Iterator) setIterator} method is
++     * invoked.
++     */
++    public TransformIterator() {
++        super();
++    }
++
++    /**
++     * Constructs a new <code>TransformIterator</code> that won't transform
++     * elements from the given iterator.
++     *
++     * @param iterator the iterator to use
++     */
++    public TransformIterator(Iterator<I> iterator) {
++        super();
++        this.iterator = iterator;
++    }
++
++    /**
++     * Constructs a new <code>TransformIterator</code> that will use the
++     * given iterator and transformer.  If the given transformer is null,
++     * then objects will not be transformed.
++     *
++     * @param iterator    the iterator to use
++     * @param transformer the transformer to use
++     */
++    public TransformIterator(Iterator<I> iterator, Transformer<I, O> transformer) {
++        super();
++        this.iterator = iterator;
++        this.transformer = transformer;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean hasNext() {
++        return iterator.hasNext();
++    }
++
++    /**
++     * Gets the next object from the iteration, transforming it using the
++     * current transformer. If the transformer is null, no transformation
++     * occurs and the object from the iterator is returned directly.
++     *
++     * @return the next object
++     * @throws java.util.NoSuchElementException
++     *          if there are no more elements
++     */
++    public O next() {
++        return transform(iterator.next());
++    }
++
++    public void remove() {
++        iterator.remove();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the iterator this iterator is using.
++     *
++     * @return the iterator.
++     */
++    public Iterator<I> getIterator() {
++        return iterator;
++    }
++
++    /**
++     * Sets the iterator for this iterator to use.
++     * If iteration has started, this effectively resets the iterator.
++     *
++     * @param iterator the iterator to use
++     */
++    public void setIterator(Iterator<I> iterator) {
++        this.iterator = iterator;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the transformer this iterator is using.
++     *
++     * @return the transformer.
++     */
++    public Transformer<I, O> getTransformer() {
++        return transformer;
++    }
++
++    /**
++     * Sets the transformer this the iterator to use.
++     * A null transformer is a no-op transformer.
++     *
++     * @param transformer the transformer to use
++     */
++    public void setTransformer(Transformer<I, O> transformer) {
++        this.transformer = transformer;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Transforms the given object using the transformer.
++     * If the transformer is null, the original object is returned as-is.
++     *
++     * @param source the object to transform
++     * @return the transformed object
++     */
++    protected O transform(I source) {
++        if (transformer != null) {
++            return transformer.transform(source);
++        }
++        // Generics hack
++        Object sourceObj = source;
++        return (O) sourceObj;
++    }
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/UniqueFilterIterator.java
+@@ -0,0 +1,45 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.functors.UniquePredicate;
++
++import java.util.Iterator;
++
++/**
++ * A FilterIterator which only returns "unique" Objects.  Internally,
++ * the Iterator maintains a Set of objects it has already encountered,
++ * and duplicate Objects are skipped.
++ *
++ * @author Matt Hall, John Watkinson, Morgan Delagrange
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 2.1
++ */
++public class UniqueFilterIterator <E> extends FilterIterator<E> {
++
++    //-------------------------------------------------------------------------
++    
++    /**
++     * Constructs a new <code>UniqueFilterIterator</code>.
++     *
++     * @param iterator the iterator to use
++     */
++    public UniqueFilterIterator(Iterator<E> iterator) {
++        super(iterator, UniquePredicate.getInstance());
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/UnmodifiableIterator.java
+@@ -0,0 +1,80 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.Unmodifiable;
++
++import java.util.Iterator;
++
++/**
++ * Decorates an iterator such that it cannot be modified.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableIterator <E> implements Iterator<E>, Unmodifiable {
++
++    /**
++     * The iterator being decorated
++     */
++    private Iterator<E> iterator;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Decorates the specified iterator such that it cannot be modified.
++     * <p/>
++     * If the iterator is already unmodifiable it is returned directly.
++     *
++     * @param iterator the iterator to decorate
++     * @throws IllegalArgumentException if the iterator is null
++     */
++    public static <E> Iterator<E> decorate(Iterator<E> iterator) {
++        if (iterator == null) {
++            throw new IllegalArgumentException("Iterator must not be null");
++        }
++        if (iterator instanceof Unmodifiable) {
++            return iterator;
++        }
++        return new UnmodifiableIterator<E>(iterator);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor.
++     *
++     * @param iterator the iterator to decorate
++     */
++    private UnmodifiableIterator(Iterator<E> iterator) {
++        super();
++        this.iterator = iterator;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean hasNext() {
++        return iterator.hasNext();
++    }
++
++    public E next() {
++        return iterator.next();
++    }
++
++    public void remove() {
++        throw new UnsupportedOperationException("remove() is not supported");
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/UnmodifiableListIterator.java
+@@ -0,0 +1,102 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.Unmodifiable;
++
++import java.util.ListIterator;
++
++/**
++ * Decorates a list iterator such that it cannot be modified.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableListIterator <E> implements ListIterator<E>, Unmodifiable {
++
++    /**
++     * The iterator being decorated
++     */
++    private ListIterator<E> iterator;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Decorates the specified iterator such that it cannot be modified.
++     *
++     * @param iterator the iterator to decorate
++     * @throws IllegalArgumentException if the iterator is null
++     */
++    public static <E> ListIterator<E> decorate(ListIterator<E> iterator) {
++        if (iterator == null) {
++            throw new IllegalArgumentException("ListIterator must not be null");
++        }
++        if (iterator instanceof Unmodifiable) {
++            return iterator;
++        }
++        return new UnmodifiableListIterator<E>(iterator);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor.
++     *
++     * @param iterator the iterator to decorate
++     */
++    private UnmodifiableListIterator(ListIterator<E> iterator) {
++        super();
++        this.iterator = iterator;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean hasNext() {
++        return iterator.hasNext();
++    }
++
++    public E next() {
++        return iterator.next();
++    }
++
++    public int nextIndex() {
++        return iterator.nextIndex();
++    }
++
++    public boolean hasPrevious() {
++        return iterator.hasPrevious();
++    }
++
++    public E previous() {
++        return iterator.previous();
++    }
++
++    public int previousIndex() {
++        return iterator.previousIndex();
++    }
++
++    public void remove() {
++        throw new UnsupportedOperationException("remove() is not supported");
++    }
++
++    public void set(E obj) {
++        throw new UnsupportedOperationException("set() is not supported");
++    }
++
++    public void add(E obj) {
++        throw new UnsupportedOperationException("add() is not supported");
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/UnmodifiableMapIterator.java
+@@ -0,0 +1,89 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.Unmodifiable;
++
++/**
++ * Decorates a map iterator such that it cannot be modified.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableMapIterator <K,V> implements MapIterator<K, V>, Unmodifiable {
++
++    /**
++     * The iterator being decorated
++     */
++    private MapIterator<K, V> iterator;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Decorates the specified iterator such that it cannot be modified.
++     *
++     * @param iterator the iterator to decorate
++     * @throws IllegalArgumentException if the iterator is null
++     */
++    public static <K,V> MapIterator<K, V> decorate(MapIterator<K, V> iterator) {
++        if (iterator == null) {
++            throw new IllegalArgumentException("MapIterator must not be null");
++        }
++        if (iterator instanceof Unmodifiable) {
++            return iterator;
++        }
++        return new UnmodifiableMapIterator<K, V>(iterator);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor.
++     *
++     * @param iterator the iterator to decorate
++     */
++    private UnmodifiableMapIterator(MapIterator<K, V> iterator) {
++        super();
++        this.iterator = iterator;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean hasNext() {
++        return iterator.hasNext();
++    }
++
++    public K next() {
++        return iterator.next();
++    }
++
++    public K getKey() {
++        return iterator.getKey();
++    }
++
++    public V getValue() {
++        return iterator.getValue();
++    }
++
++    public V setValue(V value) {
++        throw new UnsupportedOperationException("setValue() is not supported");
++    }
++
++    public void remove() {
++        throw new UnsupportedOperationException("remove() is not supported");
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/UnmodifiableOrderedMapIterator.java
+@@ -0,0 +1,97 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 1999-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.iterators;
++
++import org.apache.commons.collections15.OrderedMapIterator;
++import org.apache.commons.collections15.Unmodifiable;
++
++/**
++ * Decorates an ordered map iterator such that it cannot be modified.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:24 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableOrderedMapIterator <K,V> implements OrderedMapIterator<K, V>, Unmodifiable {
++
++    /**
++     * The iterator being decorated
++     */
++    private OrderedMapIterator<K, V> iterator;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Decorates the specified iterator such that it cannot be modified.
++     *
++     * @param iterator the iterator to decorate
++     * @throws IllegalArgumentException if the iterator is null
++     */
++    public static <K,V> OrderedMapIterator<K, V> decorate(OrderedMapIterator<K, V> iterator) {
++        if (iterator == null) {
++            throw new IllegalArgumentException("OrderedMapIterator must not be null");
++        }
++        if (iterator instanceof Unmodifiable) {
++            return iterator;
++        }
++        return new UnmodifiableOrderedMapIterator<K, V>(iterator);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor.
++     *
++     * @param iterator the iterator to decorate
++     */
++    private UnmodifiableOrderedMapIterator(OrderedMapIterator<K, V> iterator) {
++        super();
++        this.iterator = iterator;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean hasNext() {
++        return iterator.hasNext();
++    }
++
++    public K next() {
++        return iterator.next();
++    }
++
++    public boolean hasPrevious() {
++        return iterator.hasPrevious();
++    }
++
++    public K previous() {
++        return iterator.previous();
++    }
++
++    public K getKey() {
++        return iterator.getKey();
++    }
++
++    public V getValue() {
++        return iterator.getValue();
++    }
++
++    public V setValue(V value) {
++        throw new UnsupportedOperationException("setValue() is not supported");
++    }
++
++    public void remove() {
++        throw new UnsupportedOperationException("remove() is not supported");
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/iterators/package.html
+@@ -0,0 +1,26 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:24 pents90 Exp $ -->
++ <!--
++   Copyright 2002-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<body>
++<p>
++This package contains implementations of the
++{@link java.util.Iterator Iterator} interface.
++<p>
++You may also consider using 
++{@link org.apache.commons.collections.IteratorUtils IteratorUtils},
++which is a single class that uses static methods to construct instances
++of the classes in this package.
++</body>
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/keyvalue/AbstractKeyValue.java
+@@ -0,0 +1,81 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.keyvalue;
++
++import org.apache.commons.collections15.KeyValue;
++
++/**
++ * Abstract pair class to assist with creating KeyValue and MapEntry implementations.
++ *
++ * @author James Strachan
++ * @author Michael A. Smith
++ * @author Neil O'Toole
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractKeyValue <K,V> implements KeyValue<K, V> {
++
++    /**
++     * The key
++     */
++    protected K key;
++    /**
++     * The value
++     */
++    protected V value;
++
++    /**
++     * Constructs a new pair with the specified key and given value.
++     *
++     * @param key   the key for the entry, may be null
++     * @param value the value for the entry, may be null
++     */
++    protected AbstractKeyValue(K key, V value) {
++        super();
++        this.key = key;
++        this.value = value;
++    }
++
++    /**
++     * Gets the key from the pair.
++     *
++     * @return the key
++     */
++    public K getKey() {
++        return key;
++    }
++
++    /**
++     * Gets the value from the pair.
++     *
++     * @return the value
++     */
++    public V getValue() {
++        return value;
++    }
++
++    /**
++     * Gets a debugging String view of the pair.
++     *
++     * @return a String view of the entry
++     */
++    public String toString() {
++        return new StringBuffer().append(getKey()).append('=').append(getValue()).toString();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/keyvalue/AbstractMapEntry.java
+@@ -0,0 +1,89 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.keyvalue;
++
++import java.util.Map;
++
++/**
++ * Abstract Pair class to assist with creating correct Map Entry implementations.
++ *
++ * @author James Strachan
++ * @author Michael A. Smith
++ * @author Neil O'Toole
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractMapEntry <K,V> extends AbstractKeyValue<K, V> implements Map.Entry<K, V> {
++
++    /**
++     * Constructs a new entry with the given key and given value.
++     *
++     * @param key   the key for the entry, may be null
++     * @param value the value for the entry, may be null
++     */
++    protected AbstractMapEntry(K key, V value) {
++        super(key, value);
++    }
++
++    // Map.Entry interface
++    //-------------------------------------------------------------------------
++    /**
++     * Sets the value stored in this Map Entry.
++     * <p/>
++     * This Map Entry is not connected to a Map, so only the local data is changed.
++     *
++     * @param value the new value
++     * @return the previous value
++     */
++    public V setValue(V value) {
++        V answer = this.value;
++        this.value = value;
++        return answer;
++    }
++
++    /**
++     * Compares this Map Entry with another Map Entry.
++     * <p/>
++     * Implemented per API documentation of {@link java.util.Map.Entry#equals(Object)}
++     *
++     * @param obj the object to compare to
++     * @return true if equal key and value
++     */
++    public boolean equals(Object obj) {
++        if (obj == this) {
++            return true;
++        }
++        if (obj instanceof Map.Entry == false) {
++            return false;
++        }
++        Map.Entry other = (Map.Entry) obj;
++        return (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) && (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue()));
++    }
++
++    /**
++     * Gets a hashCode compatible with the equals method.
++     * <p/>
++     * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}
++     *
++     * @return a suitable hash code
++     */
++    public int hashCode() {
++        return (getKey() == null ? 0 : getKey().hashCode()) ^ (getValue() == null ? 0 : getValue().hashCode());
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/keyvalue/AbstractMapEntryDecorator.java
+@@ -0,0 +1,88 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.keyvalue;
++
++import org.apache.commons.collections15.KeyValue;
++
++import java.util.Map;
++
++/**
++ * Provides a base decorator that allows additional functionality to be added
++ * to a Map Entry.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractMapEntryDecorator <K,V> implements Map.Entry<K, V>, KeyValue<K, V> {
++
++    /**
++     * The <code>Map.Entry</code> to decorate
++     */
++    protected final Map.Entry<K, V> entry;
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param entry the <code>Map.Entry</code> to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    public AbstractMapEntryDecorator(Map.Entry<K, V> entry) {
++        if (entry == null) {
++            throw new IllegalArgumentException("Map Entry must not be null");
++        }
++        this.entry = entry;
++    }
++
++    /**
++     * Gets the map being decorated.
++     *
++     * @return the decorated map
++     */
++    protected Map.Entry<K, V> getMapEntry() {
++        return entry;
++    }
++
++    //-----------------------------------------------------------------------
++    public K getKey() {
++        return entry.getKey();
++    }
++
++    public V getValue() {
++        return entry.getValue();
++    }
++
++    public V setValue(V object) {
++        return entry.setValue(object);
++    }
++
++    public boolean equals(Object object) {
++        if (object == this) {
++            return true;
++        }
++        return entry.equals(object);
++    }
++
++    public int hashCode() {
++        return entry.hashCode();
++    }
++
++    public String toString() {
++        return entry.toString();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/keyvalue/DefaultKeyValue.java
+@@ -0,0 +1,154 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.keyvalue;
++
++import org.apache.commons.collections15.KeyValue;
++
++import java.util.Map;
++
++/**
++ * A mutable KeyValue pair that does not implement MapEntry.
++ * <p/>
++ * Note that a <code>DefaultKeyValue</code> instance may not contain
++ * itself as a key or value.
++ *
++ * @author James Strachan
++ * @author Michael A. Smith
++ * @author Neil O'Toole
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class DefaultKeyValue <K,V> extends AbstractKeyValue<K, V> {
++
++    /**
++     * Constructs a new pair with a null key and null value.
++     */
++    public DefaultKeyValue() {
++        super(null, null);
++    }
++
++    /**
++     * Constructs a new pair with the specified key and given value.
++     *
++     * @param key   the key for the entry, may be null
++     * @param value the value for the entry, may be null
++     */
++    public DefaultKeyValue(final K key, final V value) {
++        super(key, value);
++    }
++
++    /**
++     * Constructs a new pair from the specified KeyValue.
++     *
++     * @param pair the pair to copy, must not be null
++     * @throws NullPointerException if the entry is null
++     */
++    public DefaultKeyValue(final KeyValue<K, V> pair) {
++        super(pair.getKey(), pair.getValue());
++    }
++
++    /**
++     * Constructs a new pair from the specified MapEntry.
++     *
++     * @param entry the entry to copy, must not be null
++     * @throws NullPointerException if the entry is null
++     */
++    public DefaultKeyValue(final Map.Entry<K, V> entry) {
++        super(entry.getKey(), entry.getValue());
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Sets the key.
++     *
++     * @param key the new key
++     * @return the old key
++     * @throws IllegalArgumentException if key is this object
++     */
++    public K setKey(final K key) {
++        if ((Object) key == this) {
++            throw new IllegalArgumentException("DefaultKeyValue may not contain itself as a key.");
++        }
++
++        final K old = this.key;
++        this.key = key;
++        return old;
++    }
++
++    /**
++     * Sets the value.
++     *
++     * @param value the new value
++     * @return the old value of the value
++     * @throws IllegalArgumentException if value is this object
++     */
++    public V setValue(final V value) {
++        if ((Object) value == this) {
++            throw new IllegalArgumentException("DefaultKeyValue may not contain itself as a value.");
++        }
++
++        final V old = this.value;
++        this.value = value;
++        return old;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns a new <code>Map.Entry</code> object with key and value from this pair.
++     *
++     * @return a MapEntry instance
++     */
++    public Map.Entry<K, V> toMapEntry() {
++        return new DefaultMapEntry<K, V>(this);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Compares this Map Entry with another Map Entry.
++     * <p/>
++     * Returns true if the compared object is also a <code>DefaultKeyValue</code>,
++     * and its key and value are equal to this object's key and value.
++     *
++     * @param obj the object to compare to
++     * @return true if equal key and value
++     */
++    public boolean equals(final Object obj) {
++        if (obj == this) {
++            return true;
++        }
++        if (obj instanceof DefaultKeyValue == false) {
++            return false;
++        }
++
++        DefaultKeyValue other = (DefaultKeyValue) obj;
++        return (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) && (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue()));
++    }
++
++    /**
++     * Gets a hashCode compatible with the equals method.
++     * <p/>
++     * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()},
++     * however subclasses may override this.
++     *
++     * @return a suitable hash code
++     */
++    public int hashCode() {
++        return (getKey() == null ? 0 : getKey().hashCode()) ^ (getValue() == null ? 0 : getValue().hashCode());
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/keyvalue/DefaultMapEntry.java
+@@ -0,0 +1,66 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.keyvalue;
++
++import org.apache.commons.collections15.KeyValue;
++
++import java.util.Map;
++
++/**
++ * A restricted implementation of {@link java.util.Map.Entry} that prevents
++ * the MapEntry contract from being broken.
++ *
++ * @author James Strachan
++ * @author Michael A. Smith
++ * @author Neil O'Toole
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public final class DefaultMapEntry <K,V> extends AbstractMapEntry<K, V> {
++
++    /**
++     * Constructs a new entry with the specified key and given value.
++     *
++     * @param key   the key for the entry, may be null
++     * @param value the value for the entry, may be null
++     */
++    public DefaultMapEntry(final K key, final V value) {
++        super(key, value);
++    }
++
++    /**
++     * Constructs a new entry from the specified KeyValue.
++     *
++     * @param pair the pair to copy, must not be null
++     * @throws NullPointerException if the entry is null
++     */
++    public DefaultMapEntry(final KeyValue<K, V> pair) {
++        super(pair.getKey(), pair.getValue());
++    }
++
++    /**
++     * Constructs a new entry from the specified MapEntry.
++     *
++     * @param entry the entry to copy, must not be null
++     * @throws NullPointerException if the entry is null
++     */
++    public DefaultMapEntry(final Map.Entry<K, V> entry) {
++        super(entry.getKey(), entry.getValue());
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/keyvalue/MultiKey.java
+@@ -0,0 +1,202 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.keyvalue;
++
++import java.io.Serializable;
++import java.util.Arrays;
++
++/**
++ * A <code>MultiKey</code> allows multiple map keys to be merged together.
++ * <p/>
++ * The purpose of this class is to avoid the need to write code to handle
++ * maps of maps. An example might be the need to lookup a filename by
++ * key and locale. The typical solution might be nested maps. This class
++ * can be used instead by creating an instance passing in the key and locale.
++ * <p/>
++ * Example usage:
++ * <pre>
++ * // populate map with data mapping key+locale to localizedText
++ * Map map = new HashMap();
++ * MultiKey multiKey = new MultiKey(key, locale);
++ * map.put(multiKey, localizedText);
++ * <p/>
++ * // later retireve the localized text
++ * MultiKey multiKey = new MultiKey(key, locale);
++ * String localizedText = (String) map.get(multiKey);
++ * </pre>
++ *
++ * @author Howard Lewis Ship
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class MultiKey <K> implements Serializable {
++    // This class could implement List, but that would confuse it's purpose
++
++    /**
++     * Serialisation version
++     */
++    private static final long serialVersionUID = 4465448607415788805L;
++
++    /**
++     * The individual keys
++     */
++    private final K[] keys;
++    /**
++     * The cached hashCode
++     */
++    private final int hashCode;
++
++    /**
++     * Constructor taking two keys.
++     * <p/>
++     * The keys should be immutable
++     * If they are not then they must not be changed after adding to the MultiKey.
++     *
++     * @param keys the keys
++     */
++    public MultiKey(K... keys) {
++        this(keys, true);
++    }
++
++    /**
++     * Constructor taking an array of keys, optionally choosing whether to clone.
++     * <p/>
++     * <b>If the array is not cloned, then it must not be modified.</b>
++     * <p/>
++     * This method is public for performance reasons only, to avoid a clone.
++     * The hashcode is calculated once here in this method.
++     * Therefore, changing the array passed in would not change the hashcode but
++     * would change the equals method, which is a bug.
++     * <p/>
++     * This is the only fully safe usage of this constructor, as the object array
++     * is never made available in a variable:
++     * <pre>
++     * new MultiKey(new Object[] {...}, false);
++     * </pre>
++     * <p/>
++     * The keys should be immutable
++     * If they are not then they must not be changed after adding to the MultiKey.
++     *
++     * @param keys      the array of keys, not null
++     * @param makeClone true to clone the array, false to assign it
++     * @throws IllegalArgumentException if the key array is null
++     * @since Commons Collections 3.1
++     */
++    public MultiKey(K[] keys, boolean makeClone) {
++        super();
++        if (keys == null) {
++            throw new IllegalArgumentException("The array of keys must not be null");
++        }
++        if (makeClone) {
++            this.keys = (K[]) keys.clone();
++        } else {
++            this.keys = keys;
++        }
++
++        int total = 0;
++        for (int i = 0; i < keys.length; i++) {
++            if (keys[i] != null) {
++                total ^= keys[i].hashCode();
++            }
++        }
++        hashCode = total;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Gets a clone of the array of keys.
++     * <p/>
++     * The keys should be immutable
++     * If they are not then they must not be changed.
++     *
++     * @return the individual keys
++     */
++    public K[] getKeys() {
++        return keys.clone();
++    }
++
++    /**
++     * Gets the key at the specified index.
++     * <p/>
++     * The key should be immutable.
++     * If it is not then it must not be changed.
++     *
++     * @param index the index to retrieve
++     * @return the key at the index
++     * @throws IndexOutOfBoundsException if the index is invalid
++     * @since Commons Collections 3.1
++     */
++    public K getKey(int index) {
++        return keys[index];
++    }
++
++    /**
++     * Gets the size of the list of keys.
++     *
++     * @return the size of the list of keys
++     * @since Commons Collections 3.1
++     */
++    public int size() {
++        return keys.length;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Compares this object to another.
++     * <p/>
++     * To be equal, the other object must be a <code>MultiKey</code> with the
++     * same number of keys which are also equal.
++     *
++     * @param other the other object to compare to
++     * @return true if equal
++     */
++    public boolean equals(Object other) {
++        if (other == this) {
++            return true;
++        }
++        if (other instanceof MultiKey) {
++            MultiKey otherMulti = (MultiKey) other;
++            return Arrays.equals(keys, otherMulti.keys);
++        }
++        return false;
++    }
++
++    /**
++     * Gets the combined hash code that is computed from all the keys.
++     * <p/>
++     * This value is computed once and then cached, so elements should not
++     * change their hash codes once created (note that this is the same
++     * constraint that would be used if the individual keys elements were
++     * themselves {@link java.util.Map Map} keys.
++     *
++     * @return the hash code
++     */
++    public int hashCode() {
++        return hashCode;
++    }
++
++    /**
++     * Gets a debugging string version of the key.
++     *
++     * @return a debugging string
++     */
++    public String toString() {
++        return "MultiKey" + Arrays.asList(keys).toString();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/keyvalue/TiedMapEntry.java
+@@ -0,0 +1,138 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.keyvalue;
++
++import org.apache.commons.collections15.KeyValue;
++
++import java.io.Serializable;
++import java.util.Map;
++
++/**
++ * A Map Entry tied to a map underneath.
++ * <p/>
++ * This can be used to enable a map entry to make changes on the underlying
++ * map, however this will probably mess up any iterators.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class TiedMapEntry <K,V> implements Map.Entry<K, V>, KeyValue<K, V>, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -8453869361373831205L;
++
++    /**
++     * The map underlying the entry/iterator
++     */
++    private final Map<K, V> map;
++    /**
++     * The key
++     */
++    private final K key;
++
++    /**
++     * Constructs a new entry with the given Map and key.
++     *
++     * @param map the map
++     * @param key the key
++     */
++    public TiedMapEntry(Map<K, V> map, K key) {
++        super();
++        this.map = map;
++        this.key = key;
++    }
++
++    // Map.Entry interface
++    //-------------------------------------------------------------------------
++    /**
++     * Gets the key of this entry
++     *
++     * @return the key
++     */
++    public K getKey() {
++        return key;
++    }
++
++    /**
++     * Gets the value of this entry direct from the map.
++     *
++     * @return the value
++     */
++    public V getValue() {
++        return map.get(key);
++    }
++
++    /**
++     * Sets the value associated with the key direct onto the map.
++     *
++     * @param value the new value
++     * @return the old value
++     * @throws IllegalArgumentException if the value is set to this map entry
++     */
++    public V setValue(V value) {
++        if ((Object) value == this) {
++            throw new IllegalArgumentException("Cannot set value to this map entry");
++        }
++
++        return map.put(key, value);
++    }
++
++    /**
++     * Compares this Map Entry with another Map Entry.
++     * <p/>
++     * Implemented per API documentation of {@link java.util.Map.Entry#equals(Object)}
++     *
++     * @param obj the object to compare to
++     * @return true if equal key and value
++     */
++    public boolean equals(Object obj) {
++        if (obj == this) {
++            return true;
++        }
++        if (obj instanceof Map.Entry == false) {
++            return false;
++        }
++        Map.Entry other = (Map.Entry) obj;
++        Object value = getValue();
++        return (key == null ? other.getKey() == null : key.equals(other.getKey())) && (value == null ? other.getValue() == null : value.equals(other.getValue()));
++    }
++
++    /**
++     * Gets a hashCode compatible with the equals method.
++     * <p/>
++     * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}
++     *
++     * @return a suitable hash code
++     */
++    public int hashCode() {
++        Object value = getValue();
++        return (getKey() == null ? 0 : getKey().hashCode()) ^ (value == null ? 0 : value.hashCode());
++    }
++
++    /**
++     * Gets a string version of the entry.
++     *
++     * @return entry as a string
++     */
++    public String toString() {
++        return getKey() + "=" + getValue();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/keyvalue/UnmodifiableMapEntry.java
+@@ -0,0 +1,75 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.keyvalue;
++
++import org.apache.commons.collections15.KeyValue;
++import org.apache.commons.collections15.Unmodifiable;
++
++import java.util.Map;
++
++/**
++ * A {@link java.util.Map.Entry} that throws UnsupportedOperationException
++ * when <code>setValue</code> is called.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableMapEntry <K,V> extends AbstractMapEntry<K, V> implements Unmodifiable {
++
++    /**
++     * Constructs a new entry with the specified key and given value.
++     *
++     * @param key   the key for the entry, may be null
++     * @param value the value for the entry, may be null
++     */
++    public UnmodifiableMapEntry(final K key, final V value) {
++        super(key, value);
++    }
++
++    /**
++     * Constructs a new entry from the specified KeyValue.
++     *
++     * @param pair the pair to copy, must not be null
++     * @throws NullPointerException if the entry is null
++     */
++    public UnmodifiableMapEntry(final KeyValue<K, V> pair) {
++        super(pair.getKey(), pair.getValue());
++    }
++
++    /**
++     * Constructs a new entry from the specified MapEntry.
++     *
++     * @param entry the entry to copy, must not be null
++     * @throws NullPointerException if the entry is null
++     */
++    public UnmodifiableMapEntry(final Map.Entry<K, V> entry) {
++        super(entry.getKey(), entry.getValue());
++    }
++
++    /**
++     * Throws UnsupportedOperationException.
++     *
++     * @param value the new value
++     * @return the previous value
++     * @throws UnsupportedOperationException always
++     */
++    public V setValue(V value) {
++        throw new UnsupportedOperationException("setValue() is not supported");
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/keyvalue/package.html
+@@ -0,0 +1,29 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:32 pents90 Exp $ -->
++ <!--
++   Copyright 2003-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<BODY>
++<p>
++This package contains implementations of collection and map related key/value classes.
++These are usually used in maps, however they can be used as data holders in any collection.
++<p>
++The following key/value designs are included:
++<ul>
++<li>Map Entry - various map entry implementations
++<li>KeyValue - a key and value pair, without map entry semantics
++<li>MultiKey - a holder of multiple keys tied together
++</ul>
++</pre>
++</BODY>
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/AbstractLinkedList.java
+@@ -0,0 +1,1018 @@
++// GenericsNote: Converted with possible improvements noted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import org.apache.commons.collections15.OrderedIterator;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.lang.reflect.Array;
++import java.util.*;
++
++/**
++ * An abstract implementation of a linked list which provides numerous points for
++ * subclasses to override.
++ * <p/>
++ * Overridable methods are provided to change the storage node and to change how
++ * nodes are added to and removed. Hopefully, all you need for unusual subclasses
++ * is here.
++ *
++ * @author Rich Dougherty
++ * @author Phil Steitz
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractLinkedList <E> implements List<E> {
++
++    /*
++     * Implementation notes:
++     * - a standard circular doubly-linked list
++     * - a marker node is stored to mark the start and the end of the list
++     * - node creation and removal always occurs through createNode() and
++     *   removeNode().
++     * - a modification count is kept, with the same semantics as
++     * {@link java.util.LinkedList}.
++     * - respects {@link AbstractList#modCount}
++     */
++
++    /**
++     * A {@link Node} which indicates the start and end of the list and does not
++     * hold a value. The value of <code>next</code> is the first item in the
++     * list. The value of of <code>previous</code> is the last item in the list.
++     */
++    protected transient Node<E> header;
++    /**
++     * The size of the list
++     */
++    protected transient int size;
++    /**
++     * Modification count for iterators
++     */
++    protected transient int modCount;
++
++    /**
++     * Constructor that does nothing intended for deserialization.
++     * <p/>
++     * If this constructor is used by a serializable subclass then the init()
++     * method must be called.
++     */
++    protected AbstractLinkedList() {
++        super();
++    }
++
++    /**
++     * Constructs a list copying data from the specified collection.
++     *
++     * @param coll the collection to copy
++     */
++    protected AbstractLinkedList(Collection<E> coll) {
++        super();
++        init();
++        addAll(coll);
++    }
++
++    /**
++     * The equivalent of a default constructor, broken out so it can be called
++     * by any constructor and by <code>readObject</code>.
++     * Subclasses which override this method should make sure they call super,
++     * so the list is initialised properly.
++     */
++    protected void init() {
++        header = createHeaderNode();
++    }
++
++    //-----------------------------------------------------------------------
++    public int size() {
++        return size;
++    }
++
++    public boolean isEmpty() {
++        return (size() == 0);
++    }
++
++    public E get(int index) {
++        Node<E> node = getNode(index, false);
++        return node.getValue();
++    }
++
++    //-----------------------------------------------------------------------
++    public Iterator<E> iterator() {
++        return listIterator();
++    }
++
++    public ListIterator<E> listIterator() {
++        return new LinkedListIterator<E>(this, 0);
++    }
++
++    public ListIterator<E> listIterator(int fromIndex) {
++        return new LinkedListIterator<E>(this, fromIndex);
++    }
++
++    //-----------------------------------------------------------------------
++    public int indexOf(Object value) {
++        int i = 0;
++        for (Node<E> node = header.next; node != header; node = node.next) {
++            if (isEqualValue(node.getValue(), (E) value)) {
++                return i;
++            }
++            i++;
++        }
++        return -1;
++    }
++
++    public int lastIndexOf(Object value) {
++        int i = size - 1;
++        for (Node<E> node = header.previous; node != header; node = node.previous) {
++            if (isEqualValue(node.getValue(), (E) value)) {
++                return i;
++            }
++            i--;
++        }
++        return -1;
++    }
++
++    public boolean contains(Object value) {
++        return indexOf(value) != -1;
++    }
++
++    public boolean containsAll(Collection<?> coll) {
++        Iterator it = coll.iterator();
++        while (it.hasNext()) {
++            if (contains(it.next()) == false) {
++                return false;
++            }
++        }
++        return true;
++    }
++
++    //-----------------------------------------------------------------------
++    public Object[] toArray() {
++        return toArray(new Object[size]);
++    }
++
++    public <T> T[] toArray(T[] array) {
++        // Extend the array if needed
++        if (array.length < size) {
++            Class componentType = array.getClass().getComponentType();
++            array = (T[]) Array.newInstance(componentType, size);
++        }
++        // Copy the values into the array
++        int i = 0;
++        for (Node<E> node = header.next; node != header; node = node.next, i++) {
++            // Can do no better than cast through Object here.
++            array[i] = (T) (Object) node.getValue();
++        }
++        // Set the value after the last value to null
++        if (array.length > size) {
++            array[size] = null;
++        }
++        return array;
++    }
++
++    /**
++     * Gets a sublist of the main list.
++     *
++     * @param fromIndexInclusive the index to start from
++     * @param toIndexExclusive   the index to end at
++     * @return the new sublist
++     */
++    public List<E> subList(int fromIndexInclusive, int toIndexExclusive) {
++        return new LinkedSubList<E>(this, fromIndexInclusive, toIndexExclusive);
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(E value) {
++        addLast(value);
++        return true;
++    }
++
++    public void add(int index, E value) {
++        Node<E> node = getNode(index, true);
++        addNodeBefore(node, value);
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        return addAll(size, coll);
++    }
++
++    public boolean addAll(int index, Collection<? extends E> coll) {
++        Node<E> node = getNode(index, true);
++        for (Iterator itr = coll.iterator(); itr.hasNext();) {
++            Object value = itr.next();
++            addNodeBefore(node, (E) value);
++        }
++        return true;
++    }
++
++    //-----------------------------------------------------------------------
++    public E remove(int index) {
++        Node<E> node = getNode(index, false);
++        E oldValue = node.getValue();
++        removeNode(node);
++        return oldValue;
++    }
++
++    public boolean remove(Object value) {
++        for (Node<E> node = header.next; node != header; node = node.next) {
++            if (isEqualValue(node.getValue(), (E) value)) {
++                removeNode(node);
++                return true;
++            }
++        }
++        return false;
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        boolean modified = false;
++        Iterator it = iterator();
++        while (it.hasNext()) {
++            if (coll.contains(it.next())) {
++                it.remove();
++                modified = true;
++            }
++        }
++        return modified;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean retainAll(Collection<?> coll) {
++        boolean modified = false;
++        Iterator it = iterator();
++        while (it.hasNext()) {
++            if (coll.contains(it.next()) == false) {
++                it.remove();
++                modified = true;
++            }
++        }
++        return modified;
++    }
++
++    public E set(int index, E value) {
++        Node<E> node = getNode(index, false);
++        E oldValue = node.getValue();
++        updateNode(node, value);
++        return oldValue;
++    }
++
++    public void clear() {
++        removeAllNodes();
++    }
++
++    //-----------------------------------------------------------------------
++    public E getFirst() {
++        Node<E> node = header.next;
++        if (node == header) {
++            throw new NoSuchElementException();
++        }
++        return node.getValue();
++    }
++
++    public E getLast() {
++        Node<E> node = header.previous;
++        if (node == header) {
++            throw new NoSuchElementException();
++        }
++        return node.getValue();
++    }
++
++    public boolean addFirst(E o) {
++        addNodeAfter(header, o);
++        return true;
++    }
++
++    public boolean addLast(E o) {
++        addNodeBefore(header, o);
++        return true;
++    }
++
++    public E removeFirst() {
++        Node<E> node = header.next;
++        if (node == header) {
++            throw new NoSuchElementException();
++        }
++        E oldValue = node.getValue();
++        removeNode(node);
++        return oldValue;
++    }
++
++    public E removeLast() {
++        Node<E> node = header.previous;
++        if (node == header) {
++            throw new NoSuchElementException();
++        }
++        E oldValue = node.getValue();
++        removeNode(node);
++        return oldValue;
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean equals(Object obj) {
++        if (obj == this) {
++            return true;
++        }
++        if (obj instanceof List == false) {
++            return false;
++        }
++        List other = (List) obj;
++        if (other.size() != size()) {
++            return false;
++        }
++        ListIterator it1 = listIterator();
++        ListIterator it2 = other.listIterator();
++        while (it1.hasNext() && it2.hasNext()) {
++            Object o1 = it1.next();
++            Object o2 = it2.next();
++            if (!(o1 == null ? o2 == null : o1.equals(o2)))
++                return false;
++        }
++        return !(it1.hasNext() || it2.hasNext());
++    }
++
++    public int hashCode() {
++        int hashCode = 1;
++        Iterator it = iterator();
++        while (it.hasNext()) {
++            Object obj = it.next();
++            hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode());
++        }
++        return hashCode;
++    }
++
++    public String toString() {
++        if (size() == 0) {
++            return "[]";
++        }
++        StringBuffer buf = new StringBuffer(16 * size());
++        buf.append("[");
++
++        Iterator it = iterator();
++        boolean hasNext = it.hasNext();
++        while (hasNext) {
++            Object value = it.next();
++            buf.append(value == this ? "(this Collection)" : value);
++            hasNext = it.hasNext();
++            if (hasNext) {
++                buf.append(", ");
++            }
++        }
++        buf.append("]");
++        return buf.toString();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Compares two values for equals.
++     * This implementation uses the equals method.
++     * Subclasses can override this to match differently.
++     *
++     * @param value1 the first value to compare, may be null
++     * @param value2 the second value to compare, may be null
++     * @return true if equal
++     */
++    protected boolean isEqualValue(E value1, E value2) {
++        return (value1 == value2 || (value1 == null ? false : value1.equals(value2)));
++    }
++
++    /**
++     * Updates the node with a new value.
++     * This implementation sets the value on the node.
++     * Subclasses can override this to record the change.
++     *
++     * @param node  node to update
++     * @param value new value of the node
++     */
++    protected void updateNode(Node<E> node, E value) {
++        node.setValue(value);
++    }
++
++    /**
++     * Creates a new node with previous, next and element all set to null.
++     * This implementation creates a new empty Node.
++     * Subclasses can override this to create a different class.
++     *
++     * @return newly created node
++     */
++    protected Node<E> createHeaderNode() {
++        return new Node<E>();
++    }
++
++    /**
++     * Creates a new node with the specified properties.
++     * This implementation creates a new Node with data.
++     * Subclasses can override this to create a different class.
++     *
++     * @param value value of the new node
++     */
++    protected Node<E> createNode(E value) {
++        return new Node<E>(value);
++    }
++
++    /**
++     * Creates a new node with the specified object as its
++     * <code>value</code> and inserts it before <code>node</code>.
++     * <p/>
++     * This implementation uses {@link #createNode(Object)} and
++     * {@link #addNode(AbstractLinkedList.Node,AbstractLinkedList.Node)}.
++     *
++     * @param node  node to insert before
++     * @param value value of the newly added node
++     * @throws NullPointerException if <code>node</code> is null
++     */
++    protected void addNodeBefore(Node<E> node, E value) {
++        Node newNode = createNode(value);
++        addNode(newNode, node);
++    }
++
++    /**
++     * Creates a new node with the specified object as its
++     * <code>value</code> and inserts it after <code>node</code>.
++     * <p/>
++     * This implementation uses {@link #createNode(Object)} and
++     * {@link #addNode(AbstractLinkedList.Node,AbstractLinkedList.Node)}.
++     *
++     * @param node  node to insert after
++     * @param value value of the newly added node
++     * @throws NullPointerException if <code>node</code> is null
++     */
++    protected void addNodeAfter(Node<E> node, E value) {
++        Node<E> newNode = createNode(value);
++        addNode(newNode, node.next);
++    }
++
++    /**
++     * Inserts a new node into the list.
++     *
++     * @param nodeToInsert     new node to insert
++     * @param insertBeforeNode node to insert before
++     * @throws NullPointerException if either node is null
++     */
++    protected void addNode(Node<E> nodeToInsert, Node<E> insertBeforeNode) {
++        nodeToInsert.next = insertBeforeNode;
++        nodeToInsert.previous = insertBeforeNode.previous;
++        insertBeforeNode.previous.next = nodeToInsert;
++        insertBeforeNode.previous = nodeToInsert;
++        size++;
++        modCount++;
++    }
++
++    /**
++     * Removes the specified node from the list.
++     *
++     * @param node the node to remove
++     * @throws NullPointerException if <code>node</code> is null
++     */
++    protected void removeNode(Node<E> node) {
++        node.previous.next = node.next;
++        node.next.previous = node.previous;
++        size--;
++        modCount++;
++    }
++
++    /**
++     * Removes all nodes by resetting the circular list marker.
++     */
++    protected void removeAllNodes() {
++        header.next = header;
++        header.previous = header;
++        size = 0;
++        modCount++;
++    }
++
++    /**
++     * Gets the node at a particular index.
++     *
++     * @param index            the index, starting from 0
++     * @param endMarkerAllowed whether or not the end marker can be returned if
++     *                         startIndex is set to the list's size
++     * @throws IndexOutOfBoundsException if the index is less than 0; equal to
++     *                                   the size of the list and endMakerAllowed is false; or greater than the
++     *                                   size of the list
++     */
++    protected Node<E> getNode(int index, boolean endMarkerAllowed) throws IndexOutOfBoundsException {
++        // Check the index is within the bounds
++        if (index < 0) {
++            throw new IndexOutOfBoundsException("Couldn't get the node: " + "index (" + index + ") less than zero.");
++        }
++        if (!endMarkerAllowed && index == size) {
++            throw new IndexOutOfBoundsException("Couldn't get the node: " + "index (" + index + ") is the size of the list.");
++        }
++        if (index > size) {
++            throw new IndexOutOfBoundsException("Couldn't get the node: " + "index (" + index + ") greater than the size of the " + "list (" + size + ").");
++        }
++        // Search the list and get the node
++        Node<E> node;
++        if (index < (size / 2)) {
++            // Search forwards
++            node = header.next;
++            for (int currentIndex = 0; currentIndex < index; currentIndex++) {
++                node = node.next;
++            }
++        } else {
++            // Search backwards
++            node = header;
++            for (int currentIndex = size; currentIndex > index; currentIndex--) {
++                node = node.previous;
++            }
++        }
++        return node;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Creates an iterator for the sublist.
++     *
++     * @param subList the sublist to get an iterator for
++     */
++    protected Iterator<E> createSubListIterator(LinkedSubList<E> subList) {
++        return createSubListListIterator(subList, 0);
++    }
++
++    /**
++     * Creates a list iterator for the sublist.
++     *
++     * @param subList   the sublist to get an iterator for
++     * @param fromIndex the index to start from, relative to the sublist
++     */
++    protected ListIterator<E> createSubListListIterator(LinkedSubList<E> subList, int fromIndex) {
++        return new LinkedSubListIterator(subList, fromIndex);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Serializes the data held in this object to the stream specified.
++     * <p/>
++     * The first serializable subclass must call this method from
++     * <code>writeObject</code>.
++     */
++    protected void doWriteObject(ObjectOutputStream outputStream) throws IOException {
++        // Write the size so we know how many nodes to read back
++        outputStream.writeInt(size());
++        for (Iterator itr = iterator(); itr.hasNext();) {
++            outputStream.writeObject(itr.next());
++        }
++    }
++
++    /**
++     * Deserializes the data held in this object to the stream specified.
++     * <p/>
++     * The first serializable subclass must call this method from
++     * <code>readObject</code>.
++     */
++    protected void doReadObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException {
++        init();
++        int size = inputStream.readInt();
++        for (int i = 0; i < size; i++) {
++            add((E) inputStream.readObject());
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * A node within the linked list.
++     * <p/>
++     * From Commons Collections 3.1, all access to the <code>value</code> property
++     * is via the methods on this class.
++     */
++    protected static class Node <T> {
++
++        /**
++         * A pointer to the node before this node
++         */
++        protected Node<T> previous;
++        /**
++         * A pointer to the node after this node
++         */
++        protected Node<T> next;
++        /**
++         * The object contained within this node
++         */
++        protected T value;
++
++        /**
++         * Constructs a new header node.
++         */
++        protected Node() {
++            super();
++            previous = this;
++            next = this;
++        }
++
++        /**
++         * Constructs a new node.
++         *
++         * @param value the value to store
++         */
++        protected Node(T value) {
++            super();
++            this.value = value;
++        }
++
++        /**
++         * Constructs a new node.
++         *
++         * @param previous the previous node in the list
++         * @param next     the next node in the list
++         * @param value    the value to store
++         */
++        protected Node(Node<T> previous, Node<T> next, T value) {
++            super();
++            this.previous = previous;
++            this.next = next;
++            this.value = value;
++        }
++
++        /**
++         * Gets the value of the node.
++         *
++         * @return the value
++         * @since Commons Collections 3.1
++         */
++        protected T getValue() {
++            return value;
++        }
++
++        /**
++         * Sets the value of the node.
++         *
++         * @param value the value
++         * @since Commons Collections 3.1
++         */
++        protected void setValue(T value) {
++            this.value = value;
++        }
++
++        /**
++         * Gets the previous node.
++         *
++         * @return the previous node
++         * @since Commons Collections 3.1
++         */
++        protected Node<T> getPreviousNode() {
++            return previous;
++        }
++
++        /**
++         * Sets the previous node.
++         *
++         * @param previous the previous node
++         * @since Commons Collections 3.1
++         */
++        protected void setPreviousNode(Node<T> previous) {
++            this.previous = previous;
++        }
++
++        /**
++         * Gets the next node.
++         *
++         * @return the next node
++         * @since Commons Collections 3.1
++         */
++        protected Node<T> getNextNode() {
++            return next;
++        }
++
++        /**
++         * Sets the next node.
++         *
++         * @param next the next node
++         * @since Commons Collections 3.1
++         */
++        protected void setNextNode(Node<T> next) {
++            this.next = next;
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * A list iterator over the linked list.
++     */
++    protected static class LinkedListIterator <E> implements ListIterator<E>, OrderedIterator<E> {
++
++        /**
++         * The parent list
++         */
++        protected final AbstractLinkedList<E> parent;
++
++        /**
++         * The node that will be returned by {@link #next()}. If this is equal
++         * to {@link AbstractLinkedList#header} then there are no more values to return.
++         */
++        protected Node<E> next;
++
++        /**
++         * The index of {@link #next}.
++         */
++        protected int nextIndex;
++
++        /**
++         * The last node that was returned by {@link #next()} or {@link
++         * #previous()}. Set to <code>null</code> if {@link #next()} or {@link
++         * #previous()} haven't been called, or if the node has been removed
++         * with {@link #remove()} or a new node added with {@link #add(Object)}.
++         * Should be accessed through {@link #getLastNodeReturned()} to enforce
++         * this behaviour.
++         */
++        protected Node<E> current;
++
++        /**
++         * The modification count that the list is expected to have. If the list
++         * doesn't have this count, then a
++         * {@link java.util.ConcurrentModificationException} may be thrown by
++         * the operations.
++         */
++        protected int expectedModCount;
++
++        /**
++         * Create a ListIterator for a list.
++         *
++         * @param parent    the parent list
++         * @param fromIndex the index to start at
++         */
++        protected LinkedListIterator(AbstractLinkedList<E> parent, int fromIndex) throws IndexOutOfBoundsException {
++            super();
++            this.parent = parent;
++            this.expectedModCount = parent.modCount;
++            this.next = parent.getNode(fromIndex, true);
++            this.nextIndex = fromIndex;
++        }
++
++        /**
++         * Checks the modification count of the list is the value that this
++         * object expects.
++         *
++         * @throws ConcurrentModificationException
++         *          If the list's modification
++         *          count isn't the value that was expected.
++         */
++        protected void checkModCount() {
++            if (parent.modCount != expectedModCount) {
++                throw new ConcurrentModificationException();
++            }
++        }
++
++        /**
++         * Gets the last node returned.
++         *
++         * @throws IllegalStateException If {@link #next()} or
++         *                               {@link #previous()} haven't been called, or if the node has been removed
++         *                               with {@link #remove()} or a new node added with {@link #add(Object)}.
++         */
++        protected Node<E> getLastNodeReturned() throws IllegalStateException {
++            if (current == null) {
++                throw new IllegalStateException();
++            }
++            return current;
++        }
++
++        public boolean hasNext() {
++            return next != parent.header;
++        }
++
++        public E next() {
++            checkModCount();
++            if (!hasNext()) {
++                throw new NoSuchElementException("No element at index " + nextIndex + ".");
++            }
++            E value = next.getValue();
++            current = next;
++            next = next.next;
++            nextIndex++;
++            return value;
++        }
++
++        public boolean hasPrevious() {
++            return next.previous != parent.header;
++        }
++
++        public E previous() {
++            checkModCount();
++            if (!hasPrevious()) {
++                throw new NoSuchElementException("Already at start of list.");
++            }
++            next = next.previous;
++            E value = next.getValue();
++            current = next;
++            nextIndex--;
++            return value;
++        }
++
++        public int nextIndex() {
++            return nextIndex;
++        }
++
++        public int previousIndex() {
++            // not normally overridden, as relative to nextIndex()
++            return nextIndex() - 1;
++        }
++
++        public void remove() {
++            checkModCount();
++            parent.removeNode(getLastNodeReturned());
++            current = null;
++            nextIndex--;
++            expectedModCount++;
++        }
++
++        public void set(E obj) {
++            checkModCount();
++            getLastNodeReturned().setValue(obj);
++        }
++
++        public void add(E obj) {
++            checkModCount();
++            parent.addNodeBefore(next, obj);
++            current = null;
++            nextIndex++;
++            expectedModCount++;
++        }
++
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * A list iterator over the linked sub list.
++     */
++    protected static class LinkedSubListIterator <E> extends LinkedListIterator<E> {
++
++        /**
++         * The parent list
++         */
++        protected final LinkedSubList<E> sub;
++
++        protected LinkedSubListIterator(LinkedSubList<E> sub, int startIndex) {
++            super(sub.parent, startIndex + sub.offset);
++            this.sub = sub;
++        }
++
++        public boolean hasNext() {
++            return (nextIndex() < sub.size);
++        }
++
++        public boolean hasPrevious() {
++            return (previousIndex() >= 0);
++        }
++
++        public int nextIndex() {
++            return (super.nextIndex() - sub.offset);
++        }
++
++        public void add(E obj) {
++            super.add(obj);
++            sub.expectedModCount = parent.modCount;
++            sub.size++;
++        }
++
++        public void remove() {
++            super.remove();
++            sub.expectedModCount = parent.modCount;
++            sub.size--;
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * The sublist implementation for AbstractLinkedList.
++     */
++    protected static class LinkedSubList <E> extends AbstractList<E> {
++        /**
++         * The main list
++         */
++        private AbstractLinkedList<E> parent;
++        /**
++         * Offset from the main list
++         */
++        private int offset;
++        /**
++         * Sublist size
++         */
++        private int size;
++        /**
++         * Sublist modCount
++         */
++        private int expectedModCount;
++
++        protected LinkedSubList(AbstractLinkedList<E> parent, int fromIndex, int toIndex) {
++            if (fromIndex < 0) {
++                throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
++            }
++            if (toIndex > parent.size()) {
++                throw new IndexOutOfBoundsException("toIndex = " + toIndex);
++            }
++            if (fromIndex > toIndex) {
++                throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")");
++            }
++            this.parent = parent;
++            this.offset = fromIndex;
++            this.size = toIndex - fromIndex;
++            this.expectedModCount = parent.modCount;
++        }
++
++        public int size() {
++            checkModCount();
++            return size;
++        }
++
++        public E get(int index) {
++            rangeCheck(index, size);
++            checkModCount();
++            return parent.get(index + offset);
++        }
++
++        public void add(int index, E obj) {
++            rangeCheck(index, size + 1);
++            checkModCount();
++            parent.add(index + offset, obj);
++            expectedModCount = parent.modCount;
++            size++;
++            LinkedSubList.this.modCount++;
++        }
++
++        public E remove(int index) {
++            rangeCheck(index, size);
++            checkModCount();
++            E result = parent.remove(index + offset);
++            expectedModCount = parent.modCount;
++            size--;
++            LinkedSubList.this.modCount++;
++            return result;
++        }
++
++        public boolean addAll(Collection<? extends E> coll) {
++            return addAll(size, coll);
++        }
++
++        public boolean addAll(int index, Collection<? extends E> coll) {
++            rangeCheck(index, size + 1);
++            int cSize = coll.size();
++            if (cSize == 0) {
++                return false;
++            }
++
++            checkModCount();
++            parent.addAll(offset + index, coll);
++            expectedModCount = parent.modCount;
++            size += cSize;
++            LinkedSubList.this.modCount++;
++            return true;
++        }
++
++        public E set(int index, E obj) {
++            rangeCheck(index, size);
++            checkModCount();
++            return parent.set(index + offset, obj);
++        }
++
++        public void clear() {
++            checkModCount();
++            Iterator it = iterator();
++            while (it.hasNext()) {
++                it.next();
++                it.remove();
++            }
++        }
++
++        public Iterator<E> iterator() {
++            checkModCount();
++            return parent.createSubListIterator(this);
++        }
++
++        public ListIterator<E> listIterator(final int index) {
++            rangeCheck(index, size + 1);
++            checkModCount();
++            return parent.createSubListListIterator(this, index);
++        }
++
++        public List subList(int fromIndexInclusive, int toIndexExclusive) {
++            return new LinkedSubList(parent, fromIndexInclusive + offset, toIndexExclusive + offset);
++        }
++
++        protected void rangeCheck(int index, int beyond) {
++            if (index < 0 || index >= beyond) {
++                throw new IndexOutOfBoundsException("Index '" + index + "' out of bounds for size '" + size + "'");
++            }
++        }
++
++        protected void checkModCount() {
++            if (parent.modCount != expectedModCount) {
++                throw new ConcurrentModificationException();
++            }
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/AbstractListDecorator.java
+@@ -0,0 +1,105 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import org.apache.commons.collections15.collection.AbstractCollectionDecorator;
++
++import java.util.Collection;
++import java.util.List;
++import java.util.ListIterator;
++
++/**
++ * Decorates another <code>List</code> to provide additional behaviour.
++ * <p/>
++ * Methods are forwarded directly to the decorated list.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractListDecorator <E> extends AbstractCollectionDecorator<E> implements List<E> {
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     *
++     * @since Commons Collections 3.1
++     */
++    protected AbstractListDecorator() {
++        super();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param list the list to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    protected AbstractListDecorator(List<E> list) {
++        super(list);
++    }
++
++    /**
++     * Gets the list being decorated.
++     *
++     * @return the decorated list
++     */
++    protected List<E> getList() {
++        return (List<E>) getCollection();
++    }
++
++    //-----------------------------------------------------------------------
++    public void add(int index, E object) {
++        getList().add(index, object);
++    }
++
++    public boolean addAll(int index, Collection<? extends E> coll) {
++        return getList().addAll(index, coll);
++    }
++
++    public E get(int index) {
++        return getList().get(index);
++    }
++
++    public int indexOf(Object object) {
++        return getList().indexOf(object);
++    }
++
++    public int lastIndexOf(Object object) {
++        return getList().lastIndexOf(object);
++    }
++
++    public ListIterator<E> listIterator() {
++        return getList().listIterator();
++    }
++
++    public ListIterator<E> listIterator(int index) {
++        return getList().listIterator(index);
++    }
++
++    public E remove(int index) {
++        return getList().remove(index);
++    }
++
++    public E set(int index, E object) {
++        return getList().set(index, object);
++    }
++
++    public List<E> subList(int fromIndex, int toIndex) {
++        return getList().subList(fromIndex, toIndex);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/AbstractSerializableListDecorator.java
+@@ -0,0 +1,70 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.List;
++
++/**
++ * Serializable subclass of AbstractListDecorator.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @since Commons Collections 3.1
++ */
++public abstract class AbstractSerializableListDecorator <E> extends AbstractListDecorator<E> implements Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 2684959196747496299L;
++
++    /**
++     * Constructor.
++     */
++    protected AbstractSerializableListDecorator(List<E> list) {
++        super(list);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the list out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(collection);
++    }
++
++    /**
++     * Read the list in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        collection = (Collection<E>) in.readObject();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/CursorableLinkedList.java
+@@ -0,0 +1,500 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.lang.ref.WeakReference;
++import java.util.*;
++
++/**
++ * A <code>List</code> implementation with a <code>ListIterator</code> that
++ * allows concurrent modifications to the underlying list.
++ * <p/>
++ * This implementation supports all of the optional {@link List} operations.
++ * It extends <code>AbstractLinkedList</code> and thus provides the
++ * stack/queue/dequeue operations available in {@link java.util.LinkedList}.
++ * <p/>
++ * The main feature of this class is the ability to modify the list and the
++ * iterator at the same time. Both the {@link #listIterator()} and {@link #cursor()}
++ * methods provides access to a <code>Cursor</code> instance which extends
++ * <code>ListIterator</code>. The cursor allows changes to the list concurrent
++ * with changes to the iterator. Note that the {@link #iterator()} method and
++ * sublists  do <b>not</b> provide this cursor behaviour.
++ * <p/>
++ * The <code>Cursor</code> class is provided partly for backwards compatibility
++ * and partly because it allows the cursor to be directly closed. Closing the
++ * cursor is optional because references are held via a <code>WeakReference</code>.
++ * For most purposes, simply modify the iterator and list at will, and then let
++ * the garbage collector to the rest.
++ * <p/>
++ * <b>Note that this implementation is not synchronized.</b>
++ *
++ * @author Rodney Waldhoff
++ * @author Janek Bogucki
++ * @author Simon Kitching
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @see java.util.LinkedList
++ * @since Commons Collections 1.0
++ */
++public class CursorableLinkedList <E> extends AbstractLinkedList<E> implements Serializable {
++
++    /**
++     * Ensure serialization compatibility
++     */
++    private static final long serialVersionUID = 8836393098519411393L;
++
++    /**
++     * A list of the cursor currently open on this list
++     */
++    protected transient List<WeakReference<Cursor<E>>> cursors = new ArrayList<WeakReference<Cursor<E>>>();
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that creates.
++     */
++    public CursorableLinkedList() {
++        super();
++        init(); // must call init() as use super();
++    }
++
++    /**
++     * Constructor that copies the specified collection
++     *
++     * @param coll the collection to copy
++     */
++    public CursorableLinkedList(Collection<E> coll) {
++        super(coll);
++    }
++
++    /**
++     * The equivalent of a default constructor called
++     * by any constructor and by <code>readObject</code>.
++     */
++    protected void init() {
++        super.init();
++        cursors = new ArrayList<WeakReference<Cursor<E>>>();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns an iterator that does <b>not</b> support concurrent modification.
++     * <p/>
++     * If the underlying list is modified while iterating using this iterator
++     * a ConcurrentModificationException will occur.
++     * The cursor behaviour is available via {@link #listIterator()}.
++     *
++     * @return a new iterator that does <b>not</b> support concurrent modification
++     */
++    public Iterator<E> iterator() {
++        return super.listIterator(0);
++    }
++
++    /**
++     * Returns a cursor iterator that allows changes to the underlying list in parallel.
++     * <p/>
++     * The cursor enables iteration and list changes to occur in any order without
++     * invalidating the iterator (from one thread). When elements are added to the
++     * list, an event is fired to all active cursors enabling them to adjust to the
++     * change in the list.
++     * <p/>
++     * When the "current" (i.e., last returned by {@link ListIterator#next}
++     * or {@link ListIterator#previous}) element of the list is removed,
++     * the cursor automatically adjusts to the change (invalidating the
++     * last returned value such that it cannot be removed).
++     *
++     * @return a new cursor iterator
++     */
++    public ListIterator<E> listIterator() {
++        return cursor(0);
++    }
++
++    /**
++     * Returns a cursor iterator that allows changes to the underlying list in parallel.
++     * <p/>
++     * The cursor enables iteration and list changes to occur in any order without
++     * invalidating the iterator (from one thread). When elements are added to the
++     * list, an event is fired to all active cursors enabling them to adjust to the
++     * change in the list.
++     * <p/>
++     * When the "current" (i.e., last returned by {@link ListIterator#next}
++     * or {@link ListIterator#previous}) element of the list is removed,
++     * the cursor automatically adjusts to the change (invalidating the
++     * last returned value such that it cannot be removed).
++     *
++     * @param fromIndex the index to start from
++     * @return a new cursor iterator
++     */
++    public ListIterator<E> listIterator(int fromIndex) {
++        return cursor(fromIndex);
++    }
++
++    /**
++     * Returns a {@link Cursor} for iterating through the elements of this list.
++     * <p/>
++     * A <code>Cursor</code> is a <code>ListIterator</code> with an additional
++     * <code>close()</code> method. Calling this method immediately discards the
++     * references to the cursor. If it is not called, then the garbage collector
++     * will still remove the reference as it is held via a <code>WeakReference</code>.
++     * <p/>
++     * The cursor enables iteration and list changes to occur in any order without
++     * invalidating the iterator (from one thread). When elements are added to the
++     * list, an event is fired to all active cursors enabling them to adjust to the
++     * change in the list.
++     * <p/>
++     * When the "current" (i.e., last returned by {@link ListIterator#next}
++     * or {@link ListIterator#previous}) element of the list is removed,
++     * the cursor automatically adjusts to the change (invalidating the
++     * last returned value such that it cannot be removed).
++     * <p/>
++     * The {@link #listIterator()} method returns the same as this method, and can
++     * be cast to a <code>Cursor</code> if the <code>close</code> method is required.
++     *
++     * @return a new cursor iterator
++     */
++    public CursorableLinkedList.Cursor<E> cursor() {
++        return cursor(0);
++    }
++
++    /**
++     * Returns a {@link Cursor} for iterating through the elements of this list
++     * starting from a specified index.
++     * <p/>
++     * A <code>Cursor</code> is a <code>ListIterator</code> with an additional
++     * <code>close()</code> method. Calling this method immediately discards the
++     * references to the cursor. If it is not called, then the garbage collector
++     * will still remove the reference as it is held via a <code>WeakReference</code>.
++     * <p/>
++     * The cursor enables iteration and list changes to occur in any order without
++     * invalidating the iterator (from one thread). When elements are added to the
++     * list, an event is fired to all active cursors enabling them to adjust to the
++     * change in the list.
++     * <p/>
++     * When the "current" (i.e., last returned by {@link ListIterator#next}
++     * or {@link ListIterator#previous}) element of the list is removed,
++     * the cursor automatically adjusts to the change (invalidating the
++     * last returned value such that it cannot be removed).
++     * <p/>
++     * The {@link #listIterator(int)} method returns the same as this method, and can
++     * be cast to a <code>Cursor</code> if the <code>close</code> method is required.
++     *
++     * @param fromIndex the index to start from
++     * @return a new cursor iterator
++     * @throws IndexOutOfBoundsException if the index is out of range
++     *                                   (index < 0 || index > size()).
++     */
++    public CursorableLinkedList.Cursor<E> cursor(int fromIndex) {
++        Cursor<E> cursor = new Cursor<E>(this, fromIndex);
++        registerCursor(cursor);
++        return cursor;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Updates the node with a new value.
++     * This implementation sets the value on the node.
++     * Subclasses can override this to record the change.
++     *
++     * @param node  node to update
++     * @param value new value of the node
++     */
++    protected void updateNode(Node<E> node, E value) {
++        super.updateNode(node, value);
++        broadcastNodeChanged(node);
++    }
++
++    /**
++     * Inserts a new node into the list.
++     *
++     * @param nodeToInsert     new node to insert
++     * @param insertBeforeNode node to insert before
++     * @throws NullPointerException if either node is null
++     */
++    protected void addNode(Node<E> nodeToInsert, Node<E> insertBeforeNode) {
++        super.addNode(nodeToInsert, insertBeforeNode);
++        broadcastNodeInserted(nodeToInsert);
++    }
++
++    /**
++     * Removes the specified node from the list.
++     *
++     * @param node the node to remove
++     * @throws NullPointerException if <code>node</code> is null
++     */
++    protected void removeNode(Node<E> node) {
++        super.removeNode(node);
++        broadcastNodeRemoved(node);
++    }
++
++    /**
++     * Removes all nodes by iteration.
++     */
++    protected void removeAllNodes() {
++        if (size() > 0) {
++            // superclass implementation would break all the iterators
++            Iterator it = iterator();
++            while (it.hasNext()) {
++                it.next();
++                it.remove();
++            }
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Registers a cursor to be notified of changes to this list.
++     *
++     * @param cursor the cursor to register
++     */
++    protected void registerCursor(Cursor<E> cursor) {
++        // We take this opportunity to clean the cursors list
++        // of WeakReference objects to garbage-collected cursors.
++        for (Iterator<WeakReference<Cursor<E>>> it = cursors.iterator(); it.hasNext();) {
++            WeakReference<Cursor<E>> ref = it.next();
++            if (ref.get() == null) {
++                it.remove();
++            }
++        }
++        cursors.add(new WeakReference<Cursor<E>>(cursor));
++    }
++
++    /**
++     * Deregisters a cursor from the list to be notified of changes.
++     *
++     * @param cursor the cursor to deregister
++     */
++    protected void unregisterCursor(Cursor<E> cursor) {
++        for (Iterator it = cursors.iterator(); it.hasNext();) {
++            WeakReference ref = (WeakReference) it.next();
++            Cursor cur = (Cursor) ref.get();
++            if (cur == null) {
++                // some other unrelated cursor object has been 
++                // garbage-collected; let's take the opportunity to
++                // clean up the cursors list anyway..
++                it.remove();
++
++            } else if (cur == cursor) {
++                ref.clear();
++                it.remove();
++                break;
++            }
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Informs all of my registered cursors that the specified
++     * element was changed.
++     *
++     * @param node the node that was changed
++     */
++    protected void broadcastNodeChanged(Node<E> node) {
++        Iterator it = cursors.iterator();
++        while (it.hasNext()) {
++            WeakReference ref = (WeakReference) it.next();
++            Cursor cursor = (Cursor) ref.get();
++            if (cursor == null) {
++                it.remove(); // clean up list
++            } else {
++                cursor.nodeChanged(node);
++            }
++        }
++    }
++
++    /**
++     * Informs all of my registered cursors that the specified
++     * element was just removed from my list.
++     *
++     * @param node the node that was changed
++     */
++    protected void broadcastNodeRemoved(Node<E> node) {
++        Iterator it = cursors.iterator();
++        while (it.hasNext()) {
++            WeakReference ref = (WeakReference) it.next();
++            Cursor cursor = (Cursor) ref.get();
++            if (cursor == null) {
++                it.remove(); // clean up list
++            } else {
++                cursor.nodeRemoved(node);
++            }
++        }
++    }
++
++    /**
++     * Informs all of my registered cursors that the specified
++     * element was just added to my list.
++     *
++     * @param node the node that was changed
++     */
++    protected void broadcastNodeInserted(Node<E> node) {
++        Iterator it = cursors.iterator();
++        while (it.hasNext()) {
++            WeakReference ref = (WeakReference) it.next();
++            Cursor cursor = (Cursor) ref.get();
++            if (cursor == null) {
++                it.remove(); // clean up list
++            } else {
++                cursor.nodeInserted(node);
++            }
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Serializes the data held in this object to the stream specified.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        doWriteObject(out);
++    }
++
++    /**
++     * Deserializes the data held in this object to the stream specified.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        doReadObject(in);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * An extended <code>ListIterator</code> that allows concurrent changes to
++     * the underlying list.
++     */
++    public static class Cursor <E> extends AbstractLinkedList.LinkedListIterator<E> {
++        /**
++         * Is the cursor valid (not closed)
++         */
++        boolean valid = true;
++        /**
++         * Is the next index valid
++         */
++        boolean nextIndexValid = true;
++
++        /**
++         * Constructs a new cursor.
++         *
++         * @param index the index to start from
++         */
++        protected Cursor(CursorableLinkedList<E> parent, int index) {
++            super(parent, index);
++            valid = true;
++        }
++
++        /**
++         * Adds an object to the list.
++         * The object added here will be the new 'previous' in the iterator.
++         *
++         * @param obj the object to add
++         */
++        public void add(E obj) {
++            super.add(obj);
++            // add on iterator does not return the added element
++            next = next.next;
++        }
++
++        /**
++         * Gets the index of the next element to be returned.
++         *
++         * @return the next index
++         */
++        public int nextIndex() {
++            if (nextIndexValid == false) {
++                if (next == parent.header) {
++                    nextIndex = parent.size();
++                } else {
++                    int pos = 0;
++                    Node temp = parent.header.next;
++                    while (temp != next) {
++                        pos++;
++                        temp = temp.next;
++                    }
++                    nextIndex = pos;
++                }
++                nextIndexValid = true;
++            }
++            return nextIndex;
++        }
++
++        /**
++         * Handle event from the list when a node has changed.
++         *
++         * @param node the node that changed
++         */
++        protected void nodeChanged(Node<E> node) {
++            // do nothing
++        }
++
++        /**
++         * Handle event from the list when a node has been removed.
++         *
++         * @param node the node that was removed
++         */
++        protected void nodeRemoved(Node<E> node) {
++            if (node == next) {
++                next = node.next;
++            } else if (node == current) {
++                current = null;
++                nextIndex--;
++            } else {
++                nextIndexValid = false;
++            }
++        }
++
++        /**
++         * Handle event from the list when a node has been added.
++         *
++         * @param node the node that was added
++         */
++        protected void nodeInserted(Node<E> node) {
++            if (node.previous == current) {
++                next = node;
++            } else if (next.previous == node) {
++                next = node;
++            } else {
++                nextIndexValid = false;
++            }
++        }
++
++        /**
++         * Override superclass modCount check, and replace it with our valid flag.
++         */
++        protected void checkModCount() {
++            if (!valid) {
++                throw new ConcurrentModificationException("Cursor closed");
++            }
++        }
++
++        /**
++         * Mark this cursor as no longer being needed. Any resources
++         * associated with this cursor are immediately released.
++         * In previous versions of this class, it was mandatory to close
++         * all cursor objects to avoid memory leaks. It is <i>no longer</i>
++         * necessary to call this close method; an instance of this class
++         * can now be treated exactly like a normal iterator.
++         */
++        public void close() {
++            if (valid) {
++                ((CursorableLinkedList) parent).unregisterCursor(this);
++                valid = false;
++            }
++        }
++    }
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/FastArrayList.java
+@@ -0,0 +1,1286 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import java.util.*;
++
++/**
++ * <p>A customized implementation of <code>java.util.ArrayList</code> designed
++ * to operate in a multithreaded environment where the large majority of
++ * method calls are read-only, instead of structural changes.  When operating
++ * in "fast" mode, read calls are non-synchronized and write calls perform the
++ * following steps:</p>
++ * <ul>
++ * <li>Clone the existing collection
++ * <li>Perform the modification on the clone
++ * <li>Replace the existing collection with the (modified) clone
++ * </ul>
++ * <p>When first created, objects of this class default to "slow" mode, where
++ * all accesses of any type are synchronized but no cloning takes place.  This
++ * is appropriate for initially populating the collection, followed by a switch
++ * to "fast" mode (by calling <code>setFast(true)</code>) after initialization
++ * is complete.</p>
++ * <p/>
++ * <p><strong>NOTE</strong>: If you are creating and accessing an
++ * <code>ArrayList</code> only within a single thread, you should use
++ * <code>java.util.ArrayList</code> directly (with no synchronization), for
++ * maximum performance.</p>
++ * <p/>
++ * <p><strong>NOTE</strong>: <i>This class is not cross-platform.
++ * Using it may cause unexpected failures on some architectures.</i>
++ * It suffers from the same problems as the double-checked locking idiom.
++ * In particular, the instruction that clones the internal collection and the
++ * instruction that sets the internal reference to the clone can be executed
++ * or perceived out-of-order.  This means that any read operation might fail
++ * unexpectedly, as it may be reading the state of the internal collection
++ * before the internal collection is fully formed.
++ * For more information on the double-checked locking idiom, see the
++ * <a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html">
++ * Double-Checked Locking Idiom Is Broken Declaration</a>.</p>
++ *
++ * @author Matt Hall, John Watkinson, Craig R. McClanahan
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 1.0
++ */
++public class FastArrayList <E> extends ArrayList<E> {
++
++
++    // ----------------------------------------------------------- Constructors
++
++
++    /**
++     * Construct a an empty list.
++     */
++    public FastArrayList() {
++
++        super();
++        this.list = new ArrayList<E>();
++
++    }
++
++
++    /**
++     * Construct an empty list with the specified capacity.
++     *
++     * @param capacity The initial capacity of the empty list
++     */
++    public FastArrayList(int capacity) {
++
++        super();
++        this.list = new ArrayList<E>(capacity);
++
++    }
++
++
++    /**
++     * Construct a list containing the elements of the specified collection,
++     * in the order they are returned by the collection's iterator.
++     *
++     * @param collection The collection whose elements initialize the contents
++     *                   of this list
++     */
++    public FastArrayList(Collection<E> collection) {
++
++        super();
++        this.list = new ArrayList<E>(collection);
++
++    }
++
++
++    // ----------------------------------------------------- Instance Variables
++
++
++    /**
++     * The underlying list we are managing.
++     */
++    protected ArrayList<E> list = null;
++
++
++    // ------------------------------------------------------------- Properties
++
++
++    /**
++     * Are we operating in "fast" mode?
++     */
++    protected boolean fast = false;
++
++
++    /**
++     * Returns true if this list is operating in fast mode.
++     *
++     * @return true if this list is operating in fast mode
++     */
++    public boolean getFast() {
++        return (this.fast);
++    }
++
++    /**
++     * Sets whether this list will operate in fast mode.
++     *
++     * @param fast true if the list should operate in fast mode
++     */
++    public void setFast(boolean fast) {
++        this.fast = fast;
++    }
++
++
++    // --------------------------------------------------------- Public Methods
++
++
++    /**
++     * Appends the specified element to the end of this list.
++     *
++     * @param element The element to be appended
++     */
++    public boolean add(E element) {
++
++        if (fast) {
++            synchronized (this) {
++                ArrayList<E> temp = (ArrayList<E>) list.clone();
++                boolean result = temp.add(element);
++                list = temp;
++                return (result);
++            }
++        } else {
++            synchronized (list) {
++                return (list.add(element));
++            }
++        }
++
++    }
++
++
++    /**
++     * Insert the specified element at the specified position in this list,
++     * and shift all remaining elements up one position.
++     *
++     * @param index   Index at which to insert this element
++     * @param element The element to be inserted
++     * @throws IndexOutOfBoundsException if the index is out of range
++     */
++    public void add(int index, E element) {
++
++        if (fast) {
++            synchronized (this) {
++                ArrayList<E> temp = (ArrayList<E>) list.clone();
++                temp.add(index, element);
++                list = temp;
++            }
++        } else {
++            synchronized (list) {
++                list.add(index, element);
++            }
++        }
++
++    }
++
++
++    /**
++     * Append all of the elements in the specified Collection to the end
++     * of this list, in the order that they are returned by the specified
++     * Collection's Iterator.
++     *
++     * @param collection The collection to be appended
++     */
++    public boolean addAll(Collection<? extends E> collection) {
++
++        if (fast) {
++            synchronized (this) {
++                ArrayList<E> temp = (ArrayList<E>) list.clone();
++                boolean result = temp.addAll(collection);
++                list = temp;
++                return (result);
++            }
++        } else {
++            synchronized (list) {
++                return (list.addAll(collection));
++            }
++        }
++
++    }
++
++
++    /**
++     * Insert all of the elements in the specified Collection at the specified
++     * position in this list, and shift any previous elements upwards as
++     * needed.
++     *
++     * @param index      Index at which insertion takes place
++     * @param collection The collection to be added
++     * @throws IndexOutOfBoundsException if the index is out of range
++     */
++    public boolean addAll(int index, Collection<? extends E> collection) {
++
++        if (fast) {
++            synchronized (this) {
++                ArrayList<E> temp = (ArrayList<E>) list.clone();
++                boolean result = temp.addAll(index, collection);
++                list = temp;
++                return (result);
++            }
++        } else {
++            synchronized (list) {
++                return (list.addAll(index, collection));
++            }
++        }
++
++    }
++
++
++    /**
++     * Remove all of the elements from this list.  The list will be empty
++     * after this call returns.
++     *
++     * @throws UnsupportedOperationException if <code>clear()</code>
++     *                                       is not supported by this list
++     */
++    public void clear() {
++
++        if (fast) {
++            synchronized (this) {
++                ArrayList<E> temp = (ArrayList<E>) list.clone();
++                temp.clear();
++                list = temp;
++            }
++        } else {
++            synchronized (list) {
++                list.clear();
++            }
++        }
++
++    }
++
++
++    /**
++     * Return a shallow copy of this <code>FastArrayList</code> instance.
++     * The elements themselves are not copied.
++     */
++    public Object clone() {
++
++        FastArrayList<E> results = null;
++        if (fast) {
++            results = new FastArrayList<E>(list);
++        } else {
++            synchronized (list) {
++                results = new FastArrayList<E>(list);
++            }
++        }
++        results.setFast(getFast());
++        return (results);
++
++    }
++
++
++    /**
++     * Return <code>true</code> if this list contains the specified element.
++     *
++     * @param element The element to test for
++     */
++    public boolean contains(Object element) {
++
++        if (fast) {
++            return (list.contains(element));
++        } else {
++            synchronized (list) {
++                return (list.contains(element));
++            }
++        }
++
++    }
++
++
++    /**
++     * Return <code>true</code> if this list contains all of the elements
++     * in the specified Collection.
++     *
++     * @param collection Collection whose elements are to be checked
++     */
++    public boolean containsAll(Collection<?> collection) {
++
++        if (fast) {
++            return (list.containsAll(collection));
++        } else {
++            synchronized (list) {
++                return (list.containsAll(collection));
++            }
++        }
++
++    }
++
++
++    /**
++     * Increase the capacity of this <code>ArrayList</code> instance, if
++     * necessary, to ensure that it can hold at least the number of elements
++     * specified by the minimum capacity argument.
++     *
++     * @param capacity The new minimum capacity
++     */
++    public void ensureCapacity(int capacity) {
++
++        if (fast) {
++            synchronized (this) {
++                ArrayList<E> temp = (ArrayList<E>) list.clone();
++                temp.ensureCapacity(capacity);
++                list = temp;
++            }
++        } else {
++            synchronized (list) {
++                list.ensureCapacity(capacity);
++            }
++        }
++
++    }
++
++
++    /**
++     * Compare the specified object with this list for equality.  This
++     * implementation uses exactly the code that is used to define the
++     * list equals function in the documentation for the
++     * <code>List.equals</code> method.
++     *
++     * @param o Object to be compared to this list
++     */
++    public boolean equals(Object o) {
++
++        // Simple tests that require no synchronization
++        if (o == this)
++            return (true);
++        else if (!(o instanceof List))
++            return (false);
++        List lo = (List) o;
++
++        // Compare the sets of elements for equality
++        if (fast) {
++            ListIterator li1 = list.listIterator();
++            ListIterator li2 = lo.listIterator();
++            while (li1.hasNext() && li2.hasNext()) {
++                Object o1 = li1.next();
++                Object o2 = li2.next();
++                if (!(o1 == null ? o2 == null : o1.equals(o2)))
++                    return (false);
++            }
++            return (!(li1.hasNext() || li2.hasNext()));
++        } else {
++            synchronized (list) {
++                ListIterator li1 = list.listIterator();
++                ListIterator li2 = lo.listIterator();
++                while (li1.hasNext() && li2.hasNext()) {
++                    Object o1 = li1.next();
++                    Object o2 = li2.next();
++                    if (!(o1 == null ? o2 == null : o1.equals(o2)))
++                        return (false);
++                }
++                return (!(li1.hasNext() || li2.hasNext()));
++            }
++        }
++
++    }
++
++
++    /**
++     * Return the element at the specified position in the list.
++     *
++     * @param index The index of the element to return
++     * @throws IndexOutOfBoundsException if the index is out of range
++     */
++    public E get(int index) {
++
++        if (fast) {
++            return (list.get(index));
++        } else {
++            synchronized (list) {
++                return (list.get(index));
++            }
++        }
++
++    }
++
++
++    /**
++     * Return the hash code value for this list.  This implementation uses
++     * exactly the code that is used to define the list hash function in the
++     * documentation for the <code>List.hashCode</code> method.
++     */
++    public int hashCode() {
++
++        if (fast) {
++            int hashCode = 1;
++            java.util.Iterator i = list.iterator();
++            while (i.hasNext()) {
++                Object o = i.next();
++                hashCode = 31 * hashCode + (o == null ? 0 : o.hashCode());
++            }
++            return (hashCode);
++        } else {
++            synchronized (list) {
++                int hashCode = 1;
++                java.util.Iterator i = list.iterator();
++                while (i.hasNext()) {
++                    Object o = i.next();
++                    hashCode = 31 * hashCode + (o == null ? 0 : o.hashCode());
++                }
++                return (hashCode);
++            }
++        }
++
++    }
++
++
++    /**
++     * Search for the first occurrence of the given argument, testing
++     * for equality using the <code>equals()</code> method, and return
++     * the corresponding index, or -1 if the object is not found.
++     *
++     * @param element The element to search for
++     */
++    public int indexOf(Object element) {
++
++        if (fast) {
++            return (list.indexOf(element));
++        } else {
++            synchronized (list) {
++                return (list.indexOf(element));
++            }
++        }
++
++    }
++
++
++    /**
++     * Test if this list has no elements.
++     */
++    public boolean isEmpty() {
++
++        if (fast) {
++            return (list.isEmpty());
++        } else {
++            synchronized (list) {
++                return (list.isEmpty());
++            }
++        }
++
++    }
++
++
++    /**
++     * Return an iterator over the elements in this list in proper sequence.
++     * <br><br>
++     * <strong>IMPLEMENTATION NOTE</strong> - If the list is operating in fast
++     * mode, an Iterator is returned, and a structural modification to the
++     * list is made, then the Iterator will continue over the previous contents
++     * of the list (at the time that the Iterator was created), rather than
++     * failing due to concurrent modifications.
++     */
++    public Iterator<E> iterator() {
++        if (fast) {
++            return new ListIter(0);
++        } else {
++            return list.iterator();
++        }
++    }
++
++
++    /**
++     * Search for the last occurrence of the given argument, testing
++     * for equality using the <code>equals()</code> method, and return
++     * the corresponding index, or -1 if the object is not found.
++     *
++     * @param element The element to search for
++     */
++    public int lastIndexOf(Object element) {
++
++        if (fast) {
++            return (list.lastIndexOf(element));
++        } else {
++            synchronized (list) {
++                return (list.lastIndexOf(element));
++            }
++        }
++
++    }
++
++
++    /**
++     * Return an iterator of the elements of this list, in proper sequence.
++     * See the implementation note on <code>iterator()</code>.
++     */
++    public ListIterator<E> listIterator() {
++        if (fast) {
++            return new ListIter(0);
++        } else {
++            return list.listIterator();
++        }
++    }
++
++
++    /**
++     * Return an iterator of the elements of this list, in proper sequence,
++     * starting at the specified position.
++     * See the implementation note on <code>iterator()</code>.
++     *
++     * @param index The starting position of the iterator to return
++     * @throws IndexOutOfBoundsException if the index is out of range
++     */
++    public ListIterator<E> listIterator(int index) {
++        if (fast) {
++            return new ListIter(index);
++        } else {
++            return list.listIterator(index);
++        }
++    }
++
++
++    /**
++     * Remove the element at the specified position in the list, and shift
++     * any subsequent elements down one position.
++     *
++     * @param index Index of the element to be removed
++     * @throws IndexOutOfBoundsException if the index is out of range
++     */
++    public E remove(int index) {
++
++        if (fast) {
++            synchronized (this) {
++                ArrayList<E> temp = (ArrayList<E>) list.clone();
++                E result = temp.remove(index);
++                list = temp;
++                return (result);
++            }
++        } else {
++            synchronized (list) {
++                return (list.remove(index));
++            }
++        }
++
++    }
++
++
++    /**
++     * Remove the first occurrence of the specified element from the list,
++     * and shift any subsequent elements down one position.
++     *
++     * @param element Element to be removed
++     */
++    public boolean remove(Object element) {
++
++        if (fast) {
++            synchronized (this) {
++                ArrayList temp = (ArrayList) list.clone();
++                boolean result = temp.remove(element);
++                list = temp;
++                return (result);
++            }
++        } else {
++            synchronized (list) {
++                return (list.remove(element));
++            }
++        }
++
++    }
++
++
++    /**
++     * Remove from this collection all of its elements that are contained
++     * in the specified collection.
++     *
++     * @param collection Collection containing elements to be removed
++     * @throws UnsupportedOperationException if this optional operation
++     *                                       is not supported by this list
++     */
++    public boolean removeAll(Collection<?> collection) {
++
++        if (fast) {
++            synchronized (this) {
++                ArrayList temp = (ArrayList) list.clone();
++                boolean result = temp.removeAll(collection);
++                list = temp;
++                return (result);
++            }
++        } else {
++            synchronized (list) {
++                return (list.removeAll(collection));
++            }
++        }
++
++    }
++
++
++    /**
++     * Remove from this collection all of its elements except those that are
++     * contained in the specified collection.
++     *
++     * @param collection Collection containing elements to be retained
++     * @throws UnsupportedOperationException if this optional operation
++     *                                       is not supported by this list
++     */
++    public boolean retainAll(Collection<?> collection) {
++
++        if (fast) {
++            synchronized (this) {
++                ArrayList temp = (ArrayList) list.clone();
++                boolean result = temp.retainAll(collection);
++                list = temp;
++                return (result);
++            }
++        } else {
++            synchronized (list) {
++                return (list.retainAll(collection));
++            }
++        }
++
++    }
++
++
++    /**
++     * Replace the element at the specified position in this list with
++     * the specified element.  Returns the previous object at that position.
++     * <br><br>
++     * <strong>IMPLEMENTATION NOTE</strong> - This operation is specifically
++     * documented to not be a structural change, so it is safe to be performed
++     * without cloning.
++     *
++     * @param index   Index of the element to replace
++     * @param element The new element to be stored
++     * @throws IndexOutOfBoundsException if the index is out of range
++     */
++    public E set(int index, E element) {
++
++        if (fast) {
++            return (list.set(index, element));
++        } else {
++            synchronized (list) {
++                return (list.set(index, element));
++            }
++        }
++
++    }
++
++
++    /**
++     * Return the number of elements in this list.
++     */
++    public int size() {
++
++        if (fast) {
++            return (list.size());
++        } else {
++            synchronized (list) {
++                return (list.size());
++            }
++        }
++
++    }
++
++
++    /**
++     * Return a view of the portion of this list between fromIndex
++     * (inclusive) and toIndex (exclusive).  The returned list is backed
++     * by this list, so non-structural changes in the returned list are
++     * reflected in this list.  The returned list supports
++     * all of the optional list operations supported by this list.
++     *
++     * @param fromIndex The starting index of the sublist view
++     * @param toIndex   The index after the end of the sublist view
++     * @throws IndexOutOfBoundsException if an index is out of range
++     */
++    public List<E> subList(int fromIndex, int toIndex) {
++        if (fast) {
++            return new SubList(fromIndex, toIndex);
++        } else {
++            return list.subList(fromIndex, toIndex);
++        }
++    }
++
++
++    /**
++     * Return an array containing all of the elements in this list in the
++     * correct order.
++     */
++    public Object[] toArray() {
++
++        if (fast) {
++            return (list.toArray());
++        } else {
++            synchronized (list) {
++                return (list.toArray());
++            }
++        }
++
++    }
++
++
++    /**
++     * Return an array containing all of the elements in this list in the
++     * correct order.  The runtime type of the returned array is that of
++     * the specified array.  If the list fits in the specified array, it is
++     * returned therein.  Otherwise, a new array is allocated with the
++     * runtime type of the specified array, and the size of this list.
++     *
++     * @param array Array defining the element type of the returned list
++     * @throws ArrayStoreException if the runtime type of <code>array</code>
++     *                             is not a supertype of the runtime type of every element in this list
++     */
++    public <T> T[] toArray(T[] array) {
++
++        if (fast) {
++            return (list.toArray(array));
++        } else {
++            synchronized (list) {
++                return (list.toArray(array));
++            }
++        }
++
++    }
++
++
++    /**
++     * Return a String representation of this object.
++     */
++    public String toString() {
++
++        StringBuffer sb = new StringBuffer("FastArrayList[");
++        sb.append(list.toString());
++        sb.append("]");
++        return (sb.toString());
++
++    }
++
++
++    /**
++     * Trim the capacity of this <code>ArrayList</code> instance to be the
++     * list's current size.  An application can use this operation to minimize
++     * the storage of an <code>ArrayList</code> instance.
++     */
++    public void trimToSize() {
++
++        if (fast) {
++            synchronized (this) {
++                ArrayList temp = (ArrayList) list.clone();
++                temp.trimToSize();
++                list = temp;
++            }
++        } else {
++            synchronized (list) {
++                list.trimToSize();
++            }
++        }
++
++    }
++
++
++    private class SubList implements List<E> {
++
++        private int first;
++        private int last;
++        private List<E> expected;
++
++
++        public SubList(int first, int last) {
++            this.first = first;
++            this.last = last;
++            this.expected = list;
++        }
++
++        private List<E> get(List<E> l) {
++            if (list != expected) {
++                throw new ConcurrentModificationException();
++            }
++            return l.subList(first, last);
++        }
++
++        public void clear() {
++            if (fast) {
++                synchronized (FastArrayList.this) {
++                    ArrayList<E> temp = (ArrayList<E>) list.clone();
++                    get(temp).clear();
++                    last = first;
++                    list = temp;
++                    expected = temp;
++                }
++            } else {
++                synchronized (list) {
++                    get(expected).clear();
++                }
++            }
++        }
++
++        public boolean remove(Object o) {
++            if (fast) {
++                synchronized (FastArrayList.this) {
++                    ArrayList temp = (ArrayList) list.clone();
++                    boolean r = get(temp).remove(o);
++                    if (r) last--;
++                    list = temp;
++                    expected = temp;
++                    return r;
++                }
++            } else {
++                synchronized (list) {
++                    return get(expected).remove(o);
++                }
++            }
++        }
++
++        public boolean removeAll(Collection<?> o) {
++            if (fast) {
++                synchronized (FastArrayList.this) {
++                    ArrayList temp = (ArrayList) list.clone();
++                    List sub = get(temp);
++                    boolean r = sub.removeAll(o);
++                    if (r) last = first + sub.size();
++                    list = temp;
++                    expected = temp;
++                    return r;
++                }
++            } else {
++                synchronized (list) {
++                    return get(expected).removeAll(o);
++                }
++            }
++        }
++
++        public boolean retainAll(Collection<?> o) {
++            if (fast) {
++                synchronized (FastArrayList.this) {
++                    ArrayList temp = (ArrayList) list.clone();
++                    List sub = get(temp);
++                    boolean r = sub.retainAll(o);
++                    if (r) last = first + sub.size();
++                    list = temp;
++                    expected = temp;
++                    return r;
++                }
++            } else {
++                synchronized (list) {
++                    return get(expected).retainAll(o);
++                }
++            }
++        }
++
++        public int size() {
++            if (fast) {
++                return get(expected).size();
++            } else {
++                synchronized (list) {
++                    return get(expected).size();
++                }
++            }
++        }
++
++
++        public boolean isEmpty() {
++            if (fast) {
++                return get(expected).isEmpty();
++            } else {
++                synchronized (list) {
++                    return get(expected).isEmpty();
++                }
++            }
++        }
++
++        public boolean contains(Object o) {
++            if (fast) {
++                return get(expected).contains(o);
++            } else {
++                synchronized (list) {
++                    return get(expected).contains(o);
++                }
++            }
++        }
++
++        public boolean containsAll(Collection<?> o) {
++            if (fast) {
++                return get(expected).containsAll(o);
++            } else {
++                synchronized (list) {
++                    return get(expected).containsAll(o);
++                }
++            }
++        }
++
++        public <T> T[] toArray(T[] o) {
++            if (fast) {
++                return get(expected).toArray(o);
++            } else {
++                synchronized (list) {
++                    return get(expected).toArray(o);
++                }
++            }
++        }
++
++        public Object[] toArray() {
++            if (fast) {
++                return get(expected).toArray();
++            } else {
++                synchronized (list) {
++                    return get(expected).toArray();
++                }
++            }
++        }
++
++
++        public boolean equals(Object o) {
++            if (o == this) return true;
++            if (fast) {
++                return get(expected).equals(o);
++            } else {
++                synchronized (list) {
++                    return get(expected).equals(o);
++                }
++            }
++        }
++
++        public int hashCode() {
++            if (fast) {
++                return get(expected).hashCode();
++            } else {
++                synchronized (list) {
++                    return get(expected).hashCode();
++                }
++            }
++        }
++
++        public boolean add(E o) {
++            if (fast) {
++                synchronized (FastArrayList.this) {
++                    ArrayList temp = (ArrayList) list.clone();
++                    boolean r = get(temp).add(o);
++                    if (r) last++;
++                    list = temp;
++                    expected = temp;
++                    return r;
++                }
++            } else {
++                synchronized (list) {
++                    return get(expected).add(o);
++                }
++            }
++        }
++
++        public boolean addAll(Collection<? extends E> o) {
++            if (fast) {
++                synchronized (FastArrayList.this) {
++                    ArrayList temp = (ArrayList) list.clone();
++                    boolean r = get(temp).addAll(o);
++                    if (r) last += o.size();
++                    list = temp;
++                    expected = temp;
++                    return r;
++                }
++            } else {
++                synchronized (list) {
++                    return get(expected).addAll(o);
++                }
++            }
++        }
++
++        public void add(int i, E o) {
++            if (fast) {
++                synchronized (FastArrayList.this) {
++                    ArrayList temp = (ArrayList) list.clone();
++                    get(temp).add(i, o);
++                    last++;
++                    list = temp;
++                    expected = temp;
++                }
++            } else {
++                synchronized (list) {
++                    get(expected).add(i, o);
++                }
++            }
++        }
++
++        public boolean addAll(int i, Collection<? extends E> o) {
++            if (fast) {
++                synchronized (FastArrayList.this) {
++                    ArrayList temp = (ArrayList) list.clone();
++                    boolean r = get(temp).addAll(i, o);
++                    list = temp;
++                    if (r) last += o.size();
++                    expected = temp;
++                    return r;
++                }
++            } else {
++                synchronized (list) {
++                    return get(expected).addAll(i, o);
++                }
++            }
++        }
++
++        public E remove(int i) {
++            if (fast) {
++                synchronized (FastArrayList.this) {
++                    ArrayList temp = (ArrayList) list.clone();
++                    E o = get(temp).remove(i);
++                    last--;
++                    list = temp;
++                    expected = temp;
++                    return o;
++                }
++            } else {
++                synchronized (list) {
++                    return get(expected).remove(i);
++                }
++            }
++        }
++
++        public E set(int i, E a) {
++            if (fast) {
++                synchronized (FastArrayList.this) {
++                    ArrayList temp = (ArrayList) list.clone();
++                    E o = get(temp).set(i, a);
++                    list = temp;
++                    expected = temp;
++                    return o;
++                }
++            } else {
++                synchronized (list) {
++                    return get(expected).set(i, a);
++                }
++            }
++        }
++
++
++        public Iterator<E> iterator() {
++            return new SubListIter(0);
++        }
++
++        public ListIterator<E> listIterator() {
++            return new SubListIter(0);
++        }
++
++        public ListIterator<E> listIterator(int i) {
++            return new SubListIter(i);
++        }
++
++
++        public E get(int i) {
++            if (fast) {
++                return get(expected).get(i);
++            } else {
++                synchronized (list) {
++                    return get(expected).get(i);
++                }
++            }
++        }
++
++        public int indexOf(Object o) {
++            if (fast) {
++                return get(expected).indexOf(o);
++            } else {
++                synchronized (list) {
++                    return get(expected).indexOf(o);
++                }
++            }
++        }
++
++
++        public int lastIndexOf(Object o) {
++            if (fast) {
++                return get(expected).lastIndexOf(o);
++            } else {
++                synchronized (list) {
++                    return get(expected).lastIndexOf(o);
++                }
++            }
++        }
++
++
++        public List<E> subList(int f, int l) {
++            if (list != expected) {
++                throw new ConcurrentModificationException();
++            }
++            return new SubList(first + f, f + l);
++        }
++
++
++        private class SubListIter implements ListIterator<E> {
++
++            private List<E> expected;
++            private ListIterator<E> iter;
++            private int lastReturnedIndex = -1;
++
++
++            public SubListIter(int i) {
++                this.expected = list;
++                this.iter = SubList.this.get(expected).listIterator(i);
++            }
++
++            private void checkMod() {
++                if (list != expected) {
++                    throw new ConcurrentModificationException();
++                }
++            }
++
++            List<E> get() {
++                return SubList.this.get(expected);
++            }
++
++            public boolean hasNext() {
++                checkMod();
++                return iter.hasNext();
++            }
++
++            public E next() {
++                checkMod();
++                lastReturnedIndex = iter.nextIndex();
++                return iter.next();
++            }
++
++            public boolean hasPrevious() {
++                checkMod();
++                return iter.hasPrevious();
++            }
++
++            public E previous() {
++                checkMod();
++                lastReturnedIndex = iter.previousIndex();
++                return iter.previous();
++            }
++
++            public int previousIndex() {
++                checkMod();
++                return iter.previousIndex();
++            }
++
++            public int nextIndex() {
++                checkMod();
++                return iter.nextIndex();
++            }
++
++            public void remove() {
++                checkMod();
++                if (lastReturnedIndex < 0) {
++                    throw new IllegalStateException();
++                }
++                get().remove(lastReturnedIndex);
++                last--;
++                expected = list;
++                iter = get().listIterator(previousIndex());
++                lastReturnedIndex = -1;
++            }
++
++            public void set(E o) {
++                checkMod();
++                if (lastReturnedIndex < 0) {
++                    throw new IllegalStateException();
++                }
++                get().set(lastReturnedIndex, o);
++                expected = list;
++                iter = get().listIterator(previousIndex() + 1);
++            }
++
++            public void add(E o) {
++                checkMod();
++                int i = nextIndex();
++                get().add(i, o);
++                last++;
++                iter = get().listIterator(i + 1);
++                lastReturnedIndex = 1;
++            }
++
++        }
++
++
++    }
++
++
++    private class ListIter implements ListIterator<E> {
++
++        private List<E> expected;
++        private ListIterator<E> iter;
++        private int lastReturnedIndex = -1;
++
++
++        public ListIter(int i) {
++            this.expected = list;
++            this.iter = get().listIterator(i);
++        }
++
++        private void checkMod() {
++            if (list != expected) {
++                throw new ConcurrentModificationException();
++            }
++        }
++
++        List get() {
++            return expected;
++        }
++
++        public boolean hasNext() {
++            checkMod();
++            return iter.hasNext();
++        }
++
++        public E next() {
++            checkMod();
++            lastReturnedIndex = iter.nextIndex();
++            return iter.next();
++        }
++
++        public boolean hasPrevious() {
++            checkMod();
++            return iter.hasPrevious();
++        }
++
++        public E previous() {
++            checkMod();
++            lastReturnedIndex = iter.previousIndex();
++            return iter.previous();
++        }
++
++        public int previousIndex() {
++            checkMod();
++            return iter.previousIndex();
++        }
++
++        public int nextIndex() {
++            checkMod();
++            return iter.nextIndex();
++        }
++
++        public void remove() {
++            checkMod();
++            if (lastReturnedIndex < 0) {
++                throw new IllegalStateException();
++            }
++            get().remove(lastReturnedIndex);
++            expected = list;
++            iter = get().listIterator(previousIndex());
++            lastReturnedIndex = -1;
++        }
++
++        public void set(E o) {
++            checkMod();
++            if (lastReturnedIndex < 0) {
++                throw new IllegalStateException();
++            }
++            get().set(lastReturnedIndex, o);
++            expected = list;
++            iter = get().listIterator(previousIndex() + 1);
++        }
++
++        public void add(E o) {
++            checkMod();
++            int i = nextIndex();
++            get().add(i, o);
++            iter = get().listIterator(i + 1);
++            lastReturnedIndex = -1;
++        }
++
++    }
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/FixedSizeList.java
+@@ -0,0 +1,164 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import org.apache.commons.collections15.BoundedCollection;
++import org.apache.commons.collections15.iterators.AbstractListIteratorDecorator;
++import org.apache.commons.collections15.iterators.UnmodifiableIterator;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.List;
++import java.util.ListIterator;
++
++/**
++ * Decorates another <code>List</code> to fix the size preventing add/remove.
++ * <p/>
++ * The add, remove, clear and retain operations are unsupported.
++ * The set method is allowed (as it doesn't change the list size).
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class FixedSizeList <E> extends AbstractSerializableListDecorator<E> implements BoundedCollection<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -2218010673611160319L;
++
++    /**
++     * Factory method to create a fixed size list.
++     *
++     * @param list the list to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    public static <E> List<E> decorate(List<E> list) {
++        return new FixedSizeList<E>(list);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param list the list to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    protected FixedSizeList(List<E> list) {
++        super(list);
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(E object) {
++        throw new UnsupportedOperationException("List is fixed size");
++    }
++
++    public void add(int index, E object) {
++        throw new UnsupportedOperationException("List is fixed size");
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        throw new UnsupportedOperationException("List is fixed size");
++    }
++
++    public boolean addAll(int index, Collection<? extends E> coll) {
++        throw new UnsupportedOperationException("List is fixed size");
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException("List is fixed size");
++    }
++
++    public E get(int index) {
++        return getList().get(index);
++    }
++
++    public int indexOf(Object object) {
++        return getList().indexOf(object);
++    }
++
++    public Iterator<E> iterator() {
++        return UnmodifiableIterator.decorate(getCollection().iterator());
++    }
++
++    public int lastIndexOf(Object object) {
++        return getList().lastIndexOf(object);
++    }
++
++    public ListIterator<E> listIterator() {
++        return new FixedSizeListIterator<E>(getList().listIterator(0));
++    }
++
++    public ListIterator<E> listIterator(int index) {
++        return new FixedSizeListIterator<E>(getList().listIterator(index));
++    }
++
++    public E remove(int index) {
++        throw new UnsupportedOperationException("List is fixed size");
++    }
++
++    public boolean remove(Object object) {
++        throw new UnsupportedOperationException("List is fixed size");
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        throw new UnsupportedOperationException("List is fixed size");
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        throw new UnsupportedOperationException("List is fixed size");
++    }
++
++    public E set(int index, E object) {
++        return getList().set(index, object);
++    }
++
++    public List<E> subList(int fromIndex, int toIndex) {
++        List<E> sub = getList().subList(fromIndex, toIndex);
++        return new FixedSizeList<E>(sub);
++    }
++
++    /**
++     * List iterator that only permits changes via set()
++     */
++    static class FixedSizeListIterator <E> extends AbstractListIteratorDecorator<E> {
++        protected FixedSizeListIterator(ListIterator<E> iterator) {
++            super(iterator);
++        }
++
++        public void remove() {
++            throw new UnsupportedOperationException("List is fixed size");
++        }
++
++        public void add(E object) {
++            throw new UnsupportedOperationException("List is fixed size");
++        }
++    }
++
++    public boolean isFull() {
++        return true;
++    }
++
++    public int maxSize() {
++        return size();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/LazyList.java
+@@ -0,0 +1,140 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import org.apache.commons.collections15.Factory;
++
++import java.util.List;
++
++/**
++ * Decorates another <code>List</code> to create objects in the list on demand.
++ * <p/>
++ * When the {@link #get(int)} method is called with an index greater than
++ * the size of the list, the list will automatically grow in size and return
++ * a new object from the specified factory. The gaps will be filled by null.
++ * If a get method call encounters a null, it will be replaced with a new
++ * object from the factory. Thus this list is unsuitable for storing null
++ * objects.
++ * <p/>
++ * For instance:
++ * <p/>
++ * <pre>
++ * Factory factory = new Factory() {
++ *     public Object create() {
++ *         return new Date();
++ *     }
++ * }
++ * List lazy = LazyList.decorate(new ArrayList(), factory);
++ * Object obj = lazy.get(3);
++ * </pre>
++ * <p/>
++ * After the above code is executed, <code>obj</code> will contain
++ * a new <code>Date</code> instance.  Furthermore, that <code>Date</code>
++ * instance is the fourth element in the list.  The first, second,
++ * and third element are all set to <code>null</code>.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Arron Bates
++ * @author Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class LazyList <E> extends AbstractSerializableListDecorator<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -1708388017160694542L;
++
++    /**
++     * The factory to use to lazily instantiate the objects
++     */
++    protected final Factory<? extends E> factory;
++
++    /**
++     * Factory method to create a lazily instantiating list.
++     *
++     * @param list    the list to decorate, must not be null
++     * @param factory the factory to use for creation, must not be null
++     * @throws IllegalArgumentException if list or factory is null
++     */
++    public static <E> List<E> decorate(List<E> list, Factory<? extends E> factory) {
++        return new LazyList<E>(list, factory);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param list    the list to decorate, must not be null
++     * @param factory the factory to use for creation, must not be null
++     * @throws IllegalArgumentException if list or factory is null
++     */
++    protected LazyList(List<E> list, Factory<? extends E> factory) {
++        super(list);
++        if (factory == null) {
++            throw new IllegalArgumentException("Factory must not be null");
++        }
++        this.factory = factory;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Decorate the get method to perform the lazy behaviour.
++     * <p/>
++     * If the requested index is greater than the current size, the list will
++     * grow to the new size and a new object will be returned from the factory.
++     * Indexes in-between the old size and the requested size are left with a
++     * placeholder that is replaced with a factory object when requested.
++     *
++     * @param index the index to retrieve
++     */
++    public E get(int index) {
++        int size = getList().size();
++        if (index < size) {
++            // within bounds, get the object
++            E object = getList().get(index);
++            if (object == null) {
++                // item is a place holder, create new one, set and return
++                object = factory.create();
++                getList().set(index, object);
++                return object;
++            } else {
++                // good and ready to go
++                return object;
++            }
++        } else {
++            // we have to grow the list
++            for (int i = size; i < index; i++) {
++                getList().add(null);
++            }
++            // create our last object, set and return
++            E object = factory.create();
++            getList().add(object);
++            return object;
++        }
++    }
++
++
++    public List<E> subList(int fromIndex, int toIndex) {
++        List<E> sub = getList().subList(fromIndex, toIndex);
++        return new LazyList<E>(sub, factory);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/NodeCachingLinkedList.java
+@@ -0,0 +1,247 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++
++/**
++ * A <code>List</code> implementation that stores a cache of internal Node objects
++ * in an effort to reduce wasteful object creation.
++ * <p/>
++ * A linked list creates one Node for each item of data added. This can result in
++ * a lot of object creation and garbage collection. This implementation seeks to
++ * avoid that by maintaining a store of cached nodes.
++ * <p/>
++ * This implementation is suitable for long-lived lists where both add and remove
++ * are used. Short-lived lists, or lists which only grow will have worse performance
++ * using this class.
++ * <p/>
++ * <b>Note that this implementation is not synchronized.</b>
++ *
++ * @author Matt Hall, John Watkinson, Jeff Varszegi
++ * @author Rich Dougherty
++ * @author Phil Steitz
++ * @author Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class NodeCachingLinkedList <E> extends AbstractLinkedList<E> implements Serializable {
++
++    /**
++     * Serialization version
++     */
++    static final long serialVersionUID = 6897789178562232073L;
++
++    /**
++     * The default value for {@link #maximumCacheSize}.
++     */
++    protected static final int DEFAULT_MAXIMUM_CACHE_SIZE = 20;
++
++    /**
++     * The first cached node, or <code>null</code> if no nodes are cached.
++     * Cached nodes are stored in a singly-linked list with
++     * <code>next</code> pointing to the next element.
++     */
++    protected transient Node<E> firstCachedNode;
++
++    /**
++     * The size of the cache.
++     */
++    protected transient int cacheSize;
++
++    /**
++     * The maximum size of the cache.
++     */
++    protected int maximumCacheSize;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that creates.
++     */
++    public NodeCachingLinkedList() {
++        this(DEFAULT_MAXIMUM_CACHE_SIZE);
++    }
++
++    /**
++     * Constructor that copies the specified collection
++     *
++     * @param coll the collection to copy
++     */
++    public NodeCachingLinkedList(Collection<E> coll) {
++        super(coll);
++        this.maximumCacheSize = DEFAULT_MAXIMUM_CACHE_SIZE;
++    }
++
++    /**
++     * Constructor that species the maximum cache size.
++     *
++     * @param maximumCacheSize the maximum cache size
++     */
++    public NodeCachingLinkedList(int maximumCacheSize) {
++        super();
++        this.maximumCacheSize = maximumCacheSize;
++        init();  // must call init() as use super();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the maximum size of the cache.
++     *
++     * @return the maximum cache size
++     */
++    protected int getMaximumCacheSize() {
++        return maximumCacheSize;
++    }
++
++    /**
++     * Sets the maximum size of the cache.
++     *
++     * @param maximumCacheSize the new maximum cache size
++     */
++    protected void setMaximumCacheSize(int maximumCacheSize) {
++        this.maximumCacheSize = maximumCacheSize;
++        shrinkCacheToMaximumSize();
++    }
++
++    /**
++     * Reduce the size of the cache to the maximum, if necessary.
++     */
++    protected void shrinkCacheToMaximumSize() {
++        // Rich Dougherty: This could be more efficient.
++        while (cacheSize > maximumCacheSize) {
++            getNodeFromCache();
++        }
++    }
++
++    /**
++     * Gets a node from the cache. If a node is returned, then the value of
++     * {@link #cacheSize} is decreased accordingly. The node that is returned
++     * will have <code>null</code> values for next, previous and element.
++     *
++     * @return a node, or <code>null</code> if there are no nodes in the cache.
++     */
++    protected Node<E> getNodeFromCache() {
++        if (cacheSize == 0) {
++            return null;
++        }
++        Node<E> cachedNode = firstCachedNode;
++        firstCachedNode = cachedNode.next;
++        cachedNode.next = null; // This should be changed anyway, but defensively
++        // set it to null.
++        cacheSize--;
++        return cachedNode;
++    }
++
++    /**
++     * Checks whether the cache is full.
++     *
++     * @return true if the cache is full
++     */
++    protected boolean isCacheFull() {
++        return cacheSize >= maximumCacheSize;
++    }
++
++    /**
++     * Adds a node to the cache, if the cache isn't full.
++     * The node's contents are cleared to so they can be garbage collected.
++     *
++     * @param node the node to add to the cache
++     */
++    protected void addNodeToCache(Node<E> node) {
++        if (isCacheFull()) {
++            // don't cache the node.
++            return;
++        }
++        // clear the node's contents and add it to the cache.
++        Node<E> nextCachedNode = firstCachedNode;
++        node.previous = null;
++        node.next = nextCachedNode;
++        node.setValue(null);
++        firstCachedNode = node;
++        cacheSize++;
++    }
++
++    //-----------------------------------------------------------------------    
++    /**
++     * Creates a new node, either by reusing one from the cache or creating
++     * a new one.
++     *
++     * @param value value of the new node
++     * @return the newly created node
++     */
++    protected Node<E> createNode(E value) {
++        Node<E> cachedNode = getNodeFromCache();
++        if (cachedNode == null) {
++            return super.createNode(value);
++        } else {
++            cachedNode.setValue(value);
++            return cachedNode;
++        }
++    }
++
++    /**
++     * Removes the node from the list, storing it in the cache for reuse
++     * if the cache is not yet full.
++     *
++     * @param node the node to remove
++     */
++    protected void removeNode(Node<E> node) {
++        super.removeNode(node);
++        addNodeToCache(node);
++    }
++
++    /**
++     * Removes all the nodes from the list, storing as many as required in the
++     * cache for reuse.
++     */
++    protected void removeAllNodes() {
++        // Add the removed nodes to the cache, then remove the rest.
++        // We can add them to the cache before removing them, since
++        // {@link AbstractLinkedList.removeAllNodes()} removes the
++        // nodes by removing references directly from {@link #header}.
++        int numberOfNodesToCache = Math.min(size, maximumCacheSize - cacheSize);
++        Node<E> node = header.next;
++        for (int currentIndex = 0; currentIndex < numberOfNodesToCache; currentIndex++) {
++            Node<E> oldNode = node;
++            node = node.next;
++            addNodeToCache(oldNode);
++        }
++        super.removeAllNodes();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Serializes the data held in this object to the stream specified.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        doWriteObject(out);
++    }
++
++    /**
++     * Deserializes the data held in this object to the stream specified.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        doReadObject(in);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/PredicatedList.java
+@@ -0,0 +1,161 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import org.apache.commons.collections15.Predicate;
++import org.apache.commons.collections15.collection.PredicatedCollection;
++import org.apache.commons.collections15.iterators.AbstractListIteratorDecorator;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.List;
++import java.util.ListIterator;
++
++/**
++ * Decorates another <code>List</code> to validate that all additions
++ * match a specified predicate.
++ * <p/>
++ * This list exists to provide validation for the decorated list.
++ * It is normally created to decorate an empty list.
++ * If an object cannot be added to the list, an IllegalArgumentException is thrown.
++ * <p/>
++ * One usage would be to ensure that no null entries are added to the list.
++ * <pre>List list = PredicatedList.decorate(new ArrayList(), NotNullPredicate.INSTANCE);</pre>
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @author Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class PredicatedList <E> extends PredicatedCollection<E> implements List<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -5722039223898659102L;
++
++    /**
++     * Factory method to create a predicated (validating) list.
++     * <p/>
++     * If there are any elements already in the list being decorated, they
++     * are validated.
++     *
++     * @param list      the list to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @throws IllegalArgumentException if list or predicate is null
++     * @throws IllegalArgumentException if the list contains invalid elements
++     */
++    public static <E> List<E> decorate(List<E> list, Predicate<? super E> predicate) {
++        return new PredicatedList<E>(list, predicate);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the list being decorated, they
++     * are validated.
++     *
++     * @param list      the list to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @throws IllegalArgumentException if list or predicate is null
++     * @throws IllegalArgumentException if the list contains invalid elements
++     */
++    protected PredicatedList(List<E> list, Predicate<? super E> predicate) {
++        super(list, predicate);
++    }
++
++    /**
++     * Gets the list being decorated.
++     *
++     * @return the decorated list
++     */
++    protected List<E> getList() {
++        return (List<E>) getCollection();
++    }
++
++    //-----------------------------------------------------------------------
++    public E get(int index) {
++        return getList().get(index);
++    }
++
++    public int indexOf(Object object) {
++        return getList().indexOf(object);
++    }
++
++    public int lastIndexOf(Object object) {
++        return getList().lastIndexOf(object);
++    }
++
++    public E remove(int index) {
++        return getList().remove(index);
++    }
++
++    //-----------------------------------------------------------------------
++    public void add(int index, E object) {
++        validate(object);
++        getList().add(index, object);
++    }
++
++    public boolean addAll(int index, Collection<? extends E> coll) {
++        for (Iterator<? extends E> it = coll.iterator(); it.hasNext();) {
++            validate(it.next());
++        }
++        return getList().addAll(index, coll);
++    }
++
++    public ListIterator<E> listIterator() {
++        return listIterator(0);
++    }
++
++    public ListIterator<E> listIterator(int i) {
++        return new PredicatedListIterator(getList().listIterator(i));
++    }
++
++    public E set(int index, E object) {
++        validate(object);
++        return getList().set(index, object);
++    }
++
++    public List<E> subList(int fromIndex, int toIndex) {
++        List<E> sub = getList().subList(fromIndex, toIndex);
++        return new PredicatedList<E>(sub, predicate);
++    }
++
++    /**
++     * Inner class Iterator for the PredicatedList
++     */
++    protected class PredicatedListIterator extends AbstractListIteratorDecorator<E> {
++
++        protected PredicatedListIterator(ListIterator<E> iterator) {
++            super(iterator);
++        }
++
++        public void add(E object) {
++            validate(object);
++            iterator.add(object);
++        }
++
++        public void set(E object) {
++            validate(object);
++            iterator.set(object);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/SetUniqueList.java
+@@ -0,0 +1,332 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import org.apache.commons.collections15.iterators.AbstractIteratorDecorator;
++import org.apache.commons.collections15.iterators.AbstractListIteratorDecorator;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.util.*;
++
++/**
++ * Decorates a <code>List</code> to ensure that no duplicates are present
++ * much like a <code>Set</code>.
++ * <p/>
++ * The <code>List</code> interface makes certain assumptions/requirements.
++ * This implementation breaks these in certain ways, but this is merely the
++ * result of rejecting duplicates.
++ * Each violation is explained in the method, but it should not affect you.
++ * <p/>
++ * The {@link org.apache.commons.collections15.set.ListOrderedSet ListOrderedSet}
++ * class provides an alternative approach, by wrapping an existing Set and
++ * retaining insertion order in the iterator.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matthew Hawthorne
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class SetUniqueList <E> extends AbstractSerializableListDecorator<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 7196982186153478694L;
++
++    /**
++     * Internal Set to maintain uniqueness.
++     */
++    protected final Set<E> set;
++
++    /**
++     * Factory method to create a SetList using the supplied list to retain order.
++     * <p/>
++     * If the list contains duplicates, these are removed (first indexed one kept).
++     * A <code>HashSet</code> is used for the set behaviour.
++     *
++     * @param list the list to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    public static <E> SetUniqueList<E> decorate(List<E> list) {
++        if (list == null) {
++            throw new IllegalArgumentException("List must not be null");
++        }
++        if (list.isEmpty()) {
++            return new SetUniqueList<E>(list, new HashSet());
++        } else {
++            List temp = new ArrayList(list);
++            list.clear();
++            SetUniqueList<E> sl = new SetUniqueList<E>(list, new HashSet());
++            sl.addAll(temp);
++            return sl;
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies) the List and specifies the set to use.
++     * <p/>
++     * The set and list must both be correctly initialised to the same elements.
++     *
++     * @param set  the set to decorate, must not be null
++     * @param list the list to decorate, must not be null
++     * @throws IllegalArgumentException if set or list is null
++     */
++    protected SetUniqueList(List<E> list, Set<E> set) {
++        super(list);
++        if (set == null) {
++            throw new IllegalArgumentException("Set must not be null");
++        }
++        this.set = set;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an unmodifiable view as a Set.
++     *
++     * @return an unmodifiable set view
++     */
++    public Set<E> asSet() {
++        return UnmodifiableSet.decorate(set);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Adds an element to the list if it is not already present.
++     * <p/>
++     * <i>(Violation)</i>
++     * The <code>List</code> interface requires that this method returns
++     * <code>true</code> always. However this class may return <code>false</code>
++     * because of the <code>Set</code> behaviour.
++     *
++     * @param object the object to add
++     * @return true if object was added
++     */
++    public boolean add(E object) {
++        // gets initial size
++        final int sizeBefore = size();
++
++        // adds element if unique
++        add(size(), object);
++
++        // compares sizes to detect if collection changed
++        return (sizeBefore != size());
++    }
++
++    /**
++     * Adds an element to a specific index in the list if it is not already present.
++     * <p/>
++     * <i>(Violation)</i>
++     * The <code>List</code> interface makes the assumption that the element is
++     * always inserted. This may not happen with this implementation.
++     *
++     * @param index  the index to insert at
++     * @param object the object to add
++     */
++    public void add(int index, E object) {
++        // adds element if it is not contained already
++        if (set.contains(object) == false) {
++            super.add(index, object);
++            set.add(object);
++        }
++    }
++
++    /**
++     * Adds an element to the end of the list if it is not already present.
++     * <p/>
++     * <i>(Violation)</i>
++     * The <code>List</code> interface makes the assumption that the element is
++     * always inserted. This may not happen with this implementation.
++     *
++     * @param coll the collection to add
++     */
++    public boolean addAll(Collection<? extends E> coll) {
++        return addAll(size(), coll);
++    }
++
++    /**
++     * Adds a collection of objects to the end of the list avoiding duplicates.
++     * <p/>
++     * Only elements that are not already in this list will be added, and
++     * duplicates from the specified collection will be ignored.
++     * <p/>
++     * <i>(Violation)</i>
++     * The <code>List</code> interface makes the assumption that the elements
++     * are always inserted. This may not happen with this implementation.
++     *
++     * @param index the index to insert at
++     * @param coll  the collection to add in iterator order
++     * @return true if this collection changed
++     */
++    public boolean addAll(int index, Collection<? extends E> coll) {
++        // gets initial size
++        final int sizeBefore = size();
++
++        // adds all elements
++        for (final Iterator it = coll.iterator(); it.hasNext();) {
++            add((E) it.next());
++        }
++
++        // compares sizes to detect if collection changed
++        return sizeBefore != size();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Sets the value at the specified index avoiding duplicates.
++     * <p/>
++     * The object is set into the specified index.
++     * Afterwards, any previous duplicate is removed
++     * If the object is not already in the list then a normal set occurs.
++     * If it is present, then the old version is removed and re-added at this index
++     *
++     * @param index  the index to insert at
++     * @param object the object to set
++     * @return the previous object
++     */
++    public E set(int index, E object) {
++        int pos = indexOf(object);
++        E result = super.set(index, object);
++        if (pos == -1 || pos == index) {
++            return result;
++        }
++        return remove(pos);
++    }
++
++    public boolean remove(Object object) {
++        boolean result = super.remove(object);
++        set.remove(object);
++        return result;
++    }
++
++    public E remove(int index) {
++        E result = super.remove(index);
++        set.remove(result);
++        return result;
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        boolean result = super.removeAll(coll);
++        set.removeAll(coll);
++        return result;
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        boolean result = super.retainAll(coll);
++        set.retainAll(coll);
++        return result;
++    }
++
++    public void clear() {
++        super.clear();
++        set.clear();
++    }
++
++    public boolean contains(Object object) {
++        return set.contains(object);
++    }
++
++    public boolean containsAll(Collection<?> coll) {
++        return set.containsAll(coll);
++    }
++
++    public Iterator<E> iterator() {
++        return new SetListIterator(super.iterator(), set);
++    }
++
++    public ListIterator<E> listIterator() {
++        return new SetListListIterator(super.listIterator(), set);
++    }
++
++    public ListIterator<E> listIterator(int index) {
++        return new SetListListIterator(super.listIterator(index), set);
++    }
++
++    public List<E> subList(int fromIndex, int toIndex) {
++        return new SetUniqueList<E>(super.subList(fromIndex, toIndex), set);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Inner class iterator.
++     */
++    static class SetListIterator <E> extends AbstractIteratorDecorator<E> {
++
++        protected final Set<E> set;
++        protected E last = null;
++
++        protected SetListIterator(Iterator<E> it, Set<E> set) {
++            super(it);
++            this.set = set;
++        }
++
++        public E next() {
++            last = super.next();
++            return last;
++        }
++
++        public void remove() {
++            super.remove();
++            set.remove(last);
++            last = null;
++        }
++    }
++
++    /**
++     * Inner class iterator.
++     */
++    static class SetListListIterator <E> extends AbstractListIteratorDecorator<E> {
++
++        protected final Set<E> set;
++        protected E last = null;
++
++        protected SetListListIterator(ListIterator<E> it, Set<E> set) {
++            super(it);
++            this.set = set;
++        }
++
++        public E next() {
++            last = super.next();
++            return last;
++        }
++
++        public E previous() {
++            last = super.previous();
++            return last;
++        }
++
++        public void remove() {
++            super.remove();
++            set.remove(last);
++            last = null;
++        }
++
++        public void add(E object) {
++            if (set.contains(object) == false) {
++                super.add(object);
++                set.add(object);
++            }
++        }
++
++        public void set(E object) {
++            throw new UnsupportedOperationException("ListIterator does not support set");
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/SynchronizedList.java
+@@ -0,0 +1,165 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import org.apache.commons.collections15.collection.SynchronizedCollection;
++
++import java.util.Collection;
++import java.util.List;
++import java.util.ListIterator;
++
++/**
++ * Decorates another <code>List</code> to synchronize its behaviour
++ * for a multi-threaded environment.
++ * <p/>
++ * Methods are synchronized, then forwarded to the decorated list.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class SynchronizedList <E> extends SynchronizedCollection<E> implements List<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -1403835447328619437L;
++
++    /**
++     * Factory method to create a synchronized list.
++     *
++     * @param list the list to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    public static <E> List<E> decorate(List<E> list) {
++        return new SynchronizedList<E>(list);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param list the list to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    protected SynchronizedList(List<E> list) {
++        super(list);
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param list the list to decorate, must not be null
++     * @param lock the lock to use, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    protected SynchronizedList(List<E> list, Object lock) {
++        super(list, lock);
++    }
++
++    /**
++     * Gets the decorated list.
++     *
++     * @return the decorated list
++     */
++    protected List<E> getList() {
++        return (List<E>) collection;
++    }
++
++    //-----------------------------------------------------------------------
++    public void add(int index, E object) {
++        synchronized (lock) {
++            getList().add(index, object);
++        }
++    }
++
++    public boolean addAll(int index, Collection<? extends E> coll) {
++        synchronized (lock) {
++            return getList().addAll(index, coll);
++        }
++    }
++
++    public E get(int index) {
++        synchronized (lock) {
++            return getList().get(index);
++        }
++    }
++
++    public int indexOf(Object object) {
++        synchronized (lock) {
++            return getList().indexOf(object);
++        }
++    }
++
++    public int lastIndexOf(Object object) {
++        synchronized (lock) {
++            return getList().lastIndexOf(object);
++        }
++    }
++
++    /**
++     * Iterators must be manually synchronized.
++     * <pre>
++     * synchronized (coll) {
++     *   ListIterator it = coll.listIterator();
++     *   // do stuff with iterator
++     * }
++     *
++     * @return an iterator that must be manually synchronized on the collection
++     */
++    public ListIterator<E> listIterator() {
++        return getList().listIterator();
++    }
++
++    /**
++     * Iterators must be manually synchronized.
++     * <pre>
++     * synchronized (coll) {
++     *   ListIterator it = coll.listIterator(3);
++     *   // do stuff with iterator
++     * }
++     *
++     * @return an iterator that must be manually synchronized on the collection
++     */
++    public ListIterator<E> listIterator(int index) {
++        return getList().listIterator(index);
++    }
++
++    public E remove(int index) {
++        synchronized (lock) {
++            return getList().remove(index);
++        }
++    }
++
++    public E set(int index, E object) {
++        synchronized (lock) {
++            return getList().set(index, object);
++        }
++    }
++
++    public List<E> subList(int fromIndex, int toIndex) {
++        synchronized (lock) {
++            List<E> list = getList().subList(fromIndex, toIndex);
++            // the lock is passed into the constructor here to ensure that the sublist is
++            // synchronized on the same lock as the parent list
++            return new SynchronizedList<E>(list, lock);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/TransformedList.java
+@@ -0,0 +1,168 @@
++// GenericsNote: Converted, but unfortunately very little type-safety could be achieved without breaking List and ListIterator interfaces.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import org.apache.commons.collections15.Transformer;
++import org.apache.commons.collections15.collection.TransformedCollection;
++import org.apache.commons.collections15.iterators.AbstractListIteratorDecorator;
++
++import java.util.Collection;
++import java.util.List;
++import java.util.ListIterator;
++
++/**
++ * Decorates another <code>List</code> to transform objects that are added.
++ * <p/>
++ * The add and set methods are affected by this class.
++ * Thus objects must be removed or searched for using their transformed form.
++ * For example, if the transformation converts Strings to Integers, you must
++ * use the Integer form to remove objects.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ * <p>
++ * Note: This class cannot support generics without breaking the Collection contract.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class TransformedList <I,O> extends TransformedCollection<I, O> implements List {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 1077193035000013141L;
++
++    /**
++     * Factory method to create a transforming list.
++     * <p/>
++     * If there are any elements already in the list being decorated, they
++     * are NOT transformed.
++     *
++     * @param list        the list to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @throws IllegalArgumentException if list or transformer is null
++     */
++    public static <I,O> List<O> decorate(List<I> list, Transformer<? super I, ? extends O> transformer) {
++        return new TransformedList<I, O>(list, transformer);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the list being decorated, they
++     * are NOT transformed.
++     *
++     * @param list        the list to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @throws IllegalArgumentException if list or transformer is null
++     */
++    protected TransformedList(List<I> list, Transformer<? super I, ? extends O> transformer) {
++        super(list, transformer);
++    }
++
++    /**
++     * Gets the decorated list.
++     *
++     * @return the decorated list
++     */
++    protected List<O> getList() {
++        return (List<O>) collection;
++    }
++
++    //-----------------------------------------------------------------------
++    public O get(int index) {
++        return getList().get(index);
++    }
++
++    public int indexOf(Object object) {
++        return getList().indexOf(object);
++    }
++
++    public int lastIndexOf(Object object) {
++        return getList().lastIndexOf(object);
++    }
++
++    public Object remove(int index) {
++        return getList().remove(index);
++    }
++
++    //-----------------------------------------------------------------------
++    public void add(int index, Object object) {
++        O transformed = transform((I) object);
++        getList().add(index, transformed);
++    }
++
++    /**
++     * Type-safe version of {@link #add(int, Object)} (but breaks List interface).
++     */
++    public void addTyped(int index, I object) {
++        add(index, object);
++    }
++
++    public boolean addAll(int index, Collection coll) {
++        Collection<O> transformed = transform((Collection<? extends I>) coll);
++        return getList().addAll(index, transformed);
++    }
++
++    public ListIterator<O> listIterator() {
++        return listIterator(0);
++    }
++
++    public ListIterator<O> listIterator(int i) {
++        return new TransformedListIterator(getList().listIterator(i));
++    }
++
++    public O set(int index, Object object) {
++        O transformed = transform((I) object);
++        return getList().set(index, transformed);
++    }
++
++    /**
++     * Type-safe version of {@link #set(int, Object)} (but breaks List interface).
++     */
++    public O setTyped(int index, I object) {
++        return set(index, object);
++    }
++
++    public List<O> subList(int fromIndex, int toIndex) {
++        List sub = getList().subList(fromIndex, toIndex);
++        return new TransformedList<I, O>(sub, transformer);
++    }
++
++    /**
++     * Inner class Iterator for the TransformedList
++     */
++    protected class TransformedListIterator extends AbstractListIteratorDecorator {
++
++        protected TransformedListIterator(ListIterator<O> iterator) {
++            super(iterator);
++        }
++
++        public void add(Object object) {
++            O transformed = transform((I) object);
++            iterator.add(transformed);
++        }
++
++        public void set(Object object) {
++            O transformed = transform((I) object);
++            iterator.set(transformed);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/TreeList.java
+@@ -0,0 +1,898 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import org.apache.commons.collections15.OrderedIterator;
++
++import java.util.*;
++
++/**
++ * A <code>List</code> implementation that is optimised for fast insertions and
++ * removals at any index in the list.
++ * <p/>
++ * This list implementation utilises a tree structure internally to ensure that
++ * all insertions and removals are O(log n). This provides much faster performance
++ * than both an <code>ArrayList</code> and a <code>LinkedList</code> where elements
++ * are inserted and removed repeatedly from anywhere in the list.
++ * <p/>
++ * The following relative performance statistics are indicative of this class:
++ * <pre>
++ *              get  add  insert  iterate  remove
++ * TreeList       3    5       1       2       1
++ * ArrayList      1    1      40       1      40
++ * LinkedList  5800    1     350       2     325
++ * </pre>
++ * <code>ArrayList</code> is a good general purpose list implementation.
++ * It is faster than <code>TreeList</code> for most operations except inserting
++ * and removing in the middle of the list. <code>ArrayList</code> also uses less
++ * memory as <code>TreeList</code> uses one object per entry.
++ * <p/>
++ * <code>LinkedList</code> is rarely a good choice of implementation.
++ * <code>TreeList</code> is almost always a good replacement for it, although it
++ * does use sligtly more memory.
++ *
++ * @author Matt Hall, John Watkinson, Joerg Schmuecker
++ * @author Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.1
++ */
++public class TreeList <E> extends AbstractList<E> {
++    //    add; toArray; iterator; insert; get; indexOf; remove
++    //    TreeList = 1260;7360;3080;  160;   170;3400;  170;
++    //   ArrayList =  220;1480;1760; 6870;    50;1540; 7200;
++    //  LinkedList =  270;7360;3350;55860;290720;2910;55200;
++
++    /**
++     * The root node in the AVL tree
++     */
++    private AVLNode<E> root;
++
++    /**
++     * The current size of the list
++     */
++    private int size;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructs a new empty list.
++     */
++    public TreeList() {
++        super();
++    }
++
++    /**
++     * Constructs a new empty list that copies the specified list.
++     *
++     * @param coll the collection to copy
++     * @throws NullPointerException if the collection is null
++     */
++    public TreeList(Collection<? extends E> coll) {
++        super();
++        addAll(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the element at the specified index.
++     *
++     * @param index the index to retrieve
++     * @return the element at the specified index
++     */
++    public E get(int index) {
++        checkInterval(index, 0, size() - 1);
++        return root.get(index).getValue();
++    }
++
++    /**
++     * Gets the current size of the list.
++     *
++     * @return the current size
++     */
++    public int size() {
++        return size;
++    }
++
++    /**
++     * Gets an iterator over the list.
++     *
++     * @return an iterator over the list
++     */
++    public Iterator<E> iterator() {
++        // override to go 75% faster
++        return listIterator(0);
++    }
++
++    /**
++     * Gets a ListIterator over the list.
++     *
++     * @return the new iterator
++     */
++    public ListIterator<E> listIterator() {
++        // override to go 75% faster
++        return listIterator(0);
++    }
++
++    /**
++     * Gets a ListIterator over the list.
++     *
++     * @param fromIndex the index to start from
++     * @return the new iterator
++     */
++    public ListIterator<E> listIterator(int fromIndex) {
++        // override to go 75% faster
++        // cannot use EmptyIterator as iterator.add() must work
++        checkInterval(fromIndex, 0, size());
++        return new TreeListIterator<E>(this, fromIndex);
++    }
++
++    /**
++     * Searches for the index of an object in the list.
++     *
++     * @return the index of the object, -1 if not found
++     */
++    public int indexOf(Object object) {
++        // override to go 75% faster
++        if (root == null) {
++            return -1;
++        }
++        return root.indexOf((E) object, root.relativePosition);
++    }
++
++    /**
++     * Searches for the presence of an object in the list.
++     *
++     * @return true if the object is found
++     */
++    public boolean contains(Object object) {
++        return (indexOf(object) >= 0);
++    }
++
++    /**
++     * Converts the list into an array.
++     *
++     * @return the list as an array
++     */
++    public Object[] toArray() {
++        // override to go 20% faster
++        Object[] array = new Object[size()];
++        if (root != null) {
++            root.toArray((E[]) array, root.relativePosition);
++        }
++        return array;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Adds a new element to the list.
++     *
++     * @param index the index to add before
++     * @param obj   the element to add
++     */
++    public void add(int index, E obj) {
++        modCount++;
++        checkInterval(index, 0, size());
++        if (root == null) {
++            root = new AVLNode<E>(index, obj, null, null);
++        } else {
++            root = root.insert(index, obj);
++        }
++        size++;
++    }
++
++    /**
++     * Sets the element at the specified index.
++     *
++     * @param index the index to set
++     * @param obj   the object to store at the specified index
++     * @return the previous object at that index
++     * @throws IndexOutOfBoundsException if the index is invalid
++     */
++    public E set(int index, E obj) {
++        checkInterval(index, 0, size() - 1);
++        AVLNode<E> node = root.get(index);
++        E result = node.value;
++        node.setValue(obj);
++        return result;
++    }
++
++    /**
++     * Removes the element at the specified index.
++     *
++     * @param index the index to remove
++     * @return the previous object at that index
++     */
++    public E remove(int index) {
++        modCount++;
++        checkInterval(index, 0, size() - 1);
++        E result = get(index);
++        root = root.remove(index);
++        size--;
++        return result;
++    }
++
++    /**
++     * Clears the list, removing all entries.
++     */
++    public void clear() {
++        modCount++;
++        root = null;
++        size = 0;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Checks whether the index is valid.
++     *
++     * @param index      the index to check
++     * @param startIndex the first allowed index
++     * @param endIndex   the last allowed index
++     * @throws IndexOutOfBoundsException if the index is invalid
++     */
++    private void checkInterval(int index, int startIndex, int endIndex) {
++        if (index < startIndex || index > endIndex) {
++            throw new IndexOutOfBoundsException("Invalid index:" + index + ", size=" + size());
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Implements an AVLNode which keeps the offset updated.
++     * <p/>
++     * This node contains the real work.
++     * TreeList is just there to implement {@link java.util.List}.
++     * The nodes don't know the index of the object they are holding.  They
++     * do know however their position relative to their parent node.
++     * This allows to calculate the index of a node while traversing the tree.
++     * <p/>
++     * The Faedelung calculation stores a flag for both the left and right child
++     * to indicate if they are a child (false) or a link as in linked list (true).
++     */
++    static class AVLNode <T> {
++        /**
++         * The left child node or the predecessor if {@link #leftIsPrevious}.
++         */
++        private AVLNode<T> left;
++        /**
++         * Flag indicating that left reference is not a subtree but the predecessor.
++         */
++        private boolean leftIsPrevious;
++        /**
++         * The right child node or the successor if {@link #rightIsNext}.
++         */
++        private AVLNode<T> right;
++        /**
++         * Flag indicating that right reference is not a subtree but the successor.
++         */
++        private boolean rightIsNext;
++        /**
++         * How many levels of left/right are below this one.
++         */
++        private int height;
++        /**
++         * The relative position, root holds absolute position.
++         */
++        private int relativePosition;
++        /**
++         * The stored element.
++         */
++        private T value;
++
++        /**
++         * Constructs a new node with a relative position.
++         *
++         * @param relativePosition the relative position of the node
++         * @param obj              the value for the ndoe
++         * @param rightFollower    the node with the value following this one
++         * @param leftFollower     the node with the value leading this one
++         */
++        private AVLNode(int relativePosition, T obj, AVLNode<T> rightFollower, AVLNode<T> leftFollower) {
++            this.relativePosition = relativePosition;
++            value = obj;
++            rightIsNext = true;
++            leftIsPrevious = true;
++            right = rightFollower;
++            left = leftFollower;
++        }
++
++        /**
++         * Gets the value.
++         *
++         * @return the value of this node
++         */
++        T getValue() {
++            return value;
++        }
++
++        /**
++         * Sets the value.
++         *
++         * @param obj the value to store
++         */
++        void setValue(T obj) {
++            this.value = obj;
++        }
++
++        /**
++         * Locate the element with the given index relative to the
++         * offset of the parent of this node.
++         */
++        AVLNode<T> get(int index) {
++            int indexRelativeToMe = index - relativePosition;
++
++            if (indexRelativeToMe == 0) {
++                return this;
++            }
++
++            AVLNode<T> nextNode = ((indexRelativeToMe < 0) ? getLeftSubTree() : getRightSubTree());
++            if (nextNode == null) {
++                return null;
++            }
++            return nextNode.get(indexRelativeToMe);
++        }
++
++        /**
++         * Locate the index that contains the specified object.
++         */
++        int indexOf(T object, int index) {
++            if (getLeftSubTree() != null) {
++                int result = left.indexOf(object, index + left.relativePosition);
++                if (result != -1) {
++                    return result;
++                }
++            }
++            if (value == null ? value == object : value.equals(object)) {
++                return index;
++            }
++            if (getRightSubTree() != null) {
++                return right.indexOf(object, index + right.relativePosition);
++            }
++            return -1;
++        }
++
++        /**
++         * Stores the node and its children into the array specified.
++         *
++         * @param array the array to be filled
++         * @param index the index of this node
++         */
++        void toArray(T[] array, int index) {
++            array[index] = value;
++            if (getLeftSubTree() != null) {
++                left.toArray(array, index + left.relativePosition);
++            }
++            if (getRightSubTree() != null) {
++                right.toArray(array, index + right.relativePosition);
++            }
++        }
++
++        /**
++         * Gets the next node in the list after this one.
++         *
++         * @return the next node
++         */
++        AVLNode<T> next() {
++            if (rightIsNext || right == null) {
++                return right;
++            }
++            return right.min();
++        }
++
++        /**
++         * Gets the node in the list before this one.
++         *
++         * @return the previous node
++         */
++        AVLNode<T> previous() {
++            if (leftIsPrevious || left == null) {
++                return left;
++            }
++            return left.max();
++        }
++
++        /**
++         * Inserts a node at the position index.
++         *
++         * @param index is the index of the position relative to the position of
++         *              the parent node.
++         * @param obj   is the object to be stored in the position.
++         */
++        AVLNode<T> insert(int index, T obj) {
++            int indexRelativeToMe = index - relativePosition;
++
++            if (indexRelativeToMe <= 0) {
++                return insertOnLeft(indexRelativeToMe, obj);
++            } else {
++                return insertOnRight(indexRelativeToMe, obj);
++            }
++        }
++
++        private AVLNode<T> insertOnLeft(int indexRelativeToMe, T obj) {
++            AVLNode<T> ret = this;
++
++            if (getLeftSubTree() == null) {
++                setLeft(new AVLNode<T>(-1, obj, this, left), null);
++            } else {
++                setLeft(left.insert(indexRelativeToMe, obj), null);
++            }
++
++            if (relativePosition >= 0) {
++                relativePosition++;
++            }
++            ret = balance();
++            recalcHeight();
++            return ret;
++        }
++
++        private AVLNode<T> insertOnRight(int indexRelativeToMe, T obj) {
++            AVLNode<T> ret = this;
++
++            if (getRightSubTree() == null) {
++                setRight(new AVLNode<T>(+1, obj, right, this), null);
++            } else {
++                setRight(right.insert(indexRelativeToMe, obj), null);
++            }
++            if (relativePosition < 0) {
++                relativePosition--;
++            }
++            ret = balance();
++            recalcHeight();
++            return ret;
++        }
++
++        //-----------------------------------------------------------------------
++        /**
++         * Gets the left node, returning null if its a faedelung.
++         */
++        private AVLNode<T> getLeftSubTree() {
++            return (leftIsPrevious ? null : left);
++        }
++
++        /**
++         * Gets the right node, returning null if its a faedelung.
++         */
++        private AVLNode<T> getRightSubTree() {
++            return (rightIsNext ? null : right);
++        }
++
++        /**
++         * Gets the rightmost child of this node.
++         *
++         * @return the rightmost child (greatest index)
++         */
++        private AVLNode<T> max() {
++            return (getRightSubTree() == null) ? this : right.max();
++        }
++
++        /**
++         * Gets the leftmost child of this node.
++         *
++         * @return the leftmost child (smallest index)
++         */
++        private AVLNode<T> min() {
++            return (getLeftSubTree() == null) ? this : left.min();
++        }
++
++        /**
++         * Removes the node at a given position.
++         *
++         * @param index is the index of the element to be removed relative to the position of
++         *              the parent node of the current node.
++         */
++        AVLNode<T> remove(int index) {
++            int indexRelativeToMe = index - relativePosition;
++
++            if (indexRelativeToMe == 0) {
++                return removeSelf();
++            }
++            if (indexRelativeToMe > 0) {
++                setRight(right.remove(indexRelativeToMe), right.right);
++                if (relativePosition < 0) {
++                    relativePosition++;
++                }
++            } else {
++                setLeft(left.remove(indexRelativeToMe), left.left);
++                if (relativePosition > 0) {
++                    relativePosition--;
++                }
++            }
++            recalcHeight();
++            return balance();
++        }
++
++        private AVLNode<T> removeMax() {
++            if (getRightSubTree() == null) {
++                return removeSelf();
++            }
++            setRight(right.removeMax(), right.right);
++            if (relativePosition < 0) {
++                relativePosition++;
++            }
++            recalcHeight();
++            return balance();
++        }
++
++        private AVLNode<T> removeMin() {
++            if (getLeftSubTree() == null) {
++                return removeSelf();
++            }
++            setLeft(left.removeMin(), left.left);
++            if (relativePosition > 0) {
++                relativePosition--;
++            }
++            recalcHeight();
++            return balance();
++        }
++
++        private AVLNode<T> removeSelf() {
++            if (getRightSubTree() == null && getLeftSubTree() == null)
++                return null;
++            if (getRightSubTree() == null) {
++                if (relativePosition > 0) {
++                    left.relativePosition += relativePosition + (relativePosition > 0 ? 0 : 1);
++                }
++                left.max().setRight(null, right);
++                return left;
++            }
++            if (getLeftSubTree() == null) {
++                right.relativePosition += relativePosition - (relativePosition < 0 ? 0 : 1);
++                right.min().setLeft(null, left);
++                return right;
++            }
++
++            if (heightRightMinusLeft() > 0) {
++                AVLNode<T> rightMin = right.min();
++                value = rightMin.value;
++                if (leftIsPrevious) {
++                    left = rightMin.left;
++                }
++                right = right.removeMin();
++                if (relativePosition < 0) {
++                    relativePosition++;
++                }
++            } else {
++                AVLNode<T> leftMax = left.max();
++                value = leftMax.value;
++                if (rightIsNext) {
++                    right = leftMax.right;
++                }
++                left = left.removeMax();
++                if (relativePosition > 0) {
++                    relativePosition--;
++                }
++            }
++            recalcHeight();
++            return this;
++        }
++
++        //-----------------------------------------------------------------------
++        /**
++         * Balances according to the AVL algorithm.
++         */
++        private AVLNode<T> balance() {
++            switch (heightRightMinusLeft()) {
++                case 1:
++                case 0:
++                case -1:
++                    return this;
++                case -2:
++                    if (left.heightRightMinusLeft() > 0) {
++                        setLeft(left.rotateLeft(), null);
++                    }
++                    return rotateRight();
++                case 2:
++                    if (right.heightRightMinusLeft() < 0) {
++                        setRight(right.rotateRight(), null);
++                    }
++                    return rotateLeft();
++                default :
++                    throw new RuntimeException("tree inconsistent!");
++            }
++        }
++
++        /**
++         * Gets the relative position.
++         */
++        private int getOffset(AVLNode<T> node) {
++            if (node == null) {
++                return 0;
++            }
++            return node.relativePosition;
++        }
++
++        /**
++         * Sets the relative position.
++         */
++        private int setOffset(AVLNode<T> node, int newOffest) {
++            if (node == null) {
++                return 0;
++            }
++            int oldOffset = getOffset(node);
++            node.relativePosition = newOffest;
++            return oldOffset;
++        }
++
++        /**
++         * Sets the height by calculation.
++         */
++        private void recalcHeight() {
++            height = Math.max(getLeftSubTree() == null ? -1 : getLeftSubTree().height, getRightSubTree() == null ? -1 : getRightSubTree().height) + 1;
++        }
++
++        /**
++         * Returns the height of the node or -1 if the node is null.
++         */
++        private int getHeight(AVLNode<T> node) {
++            return (node == null ? -1 : node.height);
++        }
++
++        /**
++         * Returns the height difference right - left
++         */
++        private int heightRightMinusLeft() {
++            return getHeight(getRightSubTree()) - getHeight(getLeftSubTree());
++        }
++
++        private AVLNode<T> rotateLeft() {
++            AVLNode<T> newTop = right; // can't be faedelung!
++            AVLNode<T> movedNode = getRightSubTree().getLeftSubTree();
++
++            int newTopPosition = relativePosition + getOffset(newTop);
++            int myNewPosition = -newTop.relativePosition;
++            int movedPosition = getOffset(newTop) + getOffset(movedNode);
++
++            setRight(movedNode, newTop);
++            newTop.setLeft(this, null);
++
++            setOffset(newTop, newTopPosition);
++            setOffset(this, myNewPosition);
++            setOffset(movedNode, movedPosition);
++            return newTop;
++        }
++
++        private AVLNode<T> rotateRight() {
++            AVLNode<T> newTop = left; // can't be faedelung
++            AVLNode<T> movedNode = getLeftSubTree().getRightSubTree();
++
++            int newTopPosition = relativePosition + getOffset(newTop);
++            int myNewPosition = -newTop.relativePosition;
++            int movedPosition = getOffset(newTop) + getOffset(movedNode);
++
++            setLeft(movedNode, newTop);
++            newTop.setRight(this, null);
++
++            setOffset(newTop, newTopPosition);
++            setOffset(this, myNewPosition);
++            setOffset(movedNode, movedPosition);
++            return newTop;
++        }
++
++        private void setLeft(AVLNode<T> node, AVLNode<T> previous) {
++            leftIsPrevious = (node == null);
++            left = (leftIsPrevious ? previous : node);
++            recalcHeight();
++        }
++
++        private void setRight(AVLNode<T> node, AVLNode<T> next) {
++            rightIsNext = (node == null);
++            right = (rightIsNext ? next : node);
++            recalcHeight();
++        }
++
++        //      private void checkFaedelung() {
++        //          AVLNode maxNode = left.max();
++        //          if (!maxNode.rightIsFaedelung || maxNode.right != this) {
++        //              throw new RuntimeException(maxNode + " should right-faedel to " + this);
++        //          }
++        //          AVLNode minNode = right.min();
++        //          if (!minNode.leftIsFaedelung || minNode.left != this) {
++        //              throw new RuntimeException(maxNode + " should left-faedel to " + this);
++        //          }
++        //      }
++        //
++        //        private int checkTreeDepth() {
++        //            int hright = (getRightSubTree() == null ? -1 : getRightSubTree().checkTreeDepth());
++        //            //          System.out.print("checkTreeDepth");
++        //            //          System.out.print(this);
++        //            //          System.out.print(" left: ");
++        //            //          System.out.print(_left);
++        //            //          System.out.print(" right: ");
++        //            //          System.out.println(_right);
++        //
++        //            int hleft = (left == null ? -1 : left.checkTreeDepth());
++        //            if (height != Math.max(hright, hleft) + 1) {
++        //                throw new RuntimeException(
++        //                    "height should be max" + hleft + "," + hright + " but is " + height);
++        //            }
++        //            return height;
++        //        }
++        //
++        //        private int checkLeftSubNode() {
++        //            if (getLeftSubTree() == null) {
++        //                return 0;
++        //            }
++        //            int count = 1 + left.checkRightSubNode();
++        //            if (left.relativePosition != -count) {
++        //                throw new RuntimeException();
++        //            }
++        //            return count + left.checkLeftSubNode();
++        //        }
++        //
++        //        private int checkRightSubNode() {
++        //            AVLNode right = getRightSubTree();
++        //            if (right == null) {
++        //                return 0;
++        //            }
++        //            int count = 1;
++        //            count += right.checkLeftSubNode();
++        //            if (right.relativePosition != count) {
++        //                throw new RuntimeException();
++        //            }
++        //            return count + right.checkRightSubNode();
++        //        }
++
++        /**
++         * Used for debugging.
++         */
++        public String toString() {
++            return "AVLNode(" + relativePosition + "," + (left != null) + "," + value + "," + (getRightSubTree() != null) + ", faedelung " + rightIsNext + " )";
++        }
++    }
++
++    /**
++     * A list iterator over the linked list.
++     */
++    static class TreeListIterator <E> implements ListIterator<E>, OrderedIterator<E> {
++        /**
++         * The parent list
++         */
++        protected final TreeList<E> parent;
++        /**
++         * The node that will be returned by {@link #next()}. If this is equal
++         * to {@link AbstractLinkedList#header} then there are no more values to return.
++         */
++        protected AVLNode<E> next;
++        /**
++         * The index of {@link #next}.
++         */
++        protected int nextIndex;
++        /**
++         * The last node that was returned by {@link #next()} or {@link
++         * #previous()}. Set to <code>null</code> if {@link #next()} or {@link
++         * #previous()} haven't been called, or if the node has been removed
++         * with {@link #remove()} or a new node added with {@link #add(Object)}.
++         * Should be accessed through {@link #getLastNodeReturned()} to enforce
++         * this behaviour.
++         */
++        protected AVLNode<E> current;
++        /**
++         * The index of {@link #current}.
++         */
++        protected int currentIndex;
++        /**
++         * The modification count that the list is expected to have. If the list
++         * doesn't have this count, then a
++         * {@link java.util.ConcurrentModificationException} may be thrown by
++         * the operations.
++         */
++        protected int expectedModCount;
++
++        /**
++         * Create a ListIterator for a list.
++         *
++         * @param parent    the parent list
++         * @param fromIndex the index to start at
++         */
++        protected TreeListIterator(TreeList<E> parent, int fromIndex) throws IndexOutOfBoundsException {
++            super();
++            this.parent = parent;
++            this.expectedModCount = parent.modCount;
++            this.next = (parent.root == null ? null : parent.root.get(fromIndex));
++            this.nextIndex = fromIndex;
++        }
++
++        /**
++         * Checks the modification count of the list is the value that this
++         * object expects.
++         *
++         * @throws ConcurrentModificationException
++         *          If the list's modification
++         *          count isn't the value that was expected.
++         */
++        protected void checkModCount() {
++            if (parent.modCount != expectedModCount) {
++                throw new ConcurrentModificationException();
++            }
++        }
++
++        public boolean hasNext() {
++            return (nextIndex < parent.size());
++        }
++
++        public E next() {
++            checkModCount();
++            if (!hasNext()) {
++                throw new NoSuchElementException("No element at index " + nextIndex + ".");
++            }
++            if (next == null) {
++                next = parent.root.get(nextIndex);
++            }
++            E value = next.getValue();
++            current = next;
++            currentIndex = nextIndex++;
++            next = next.next();
++            return value;
++        }
++
++        public boolean hasPrevious() {
++            return (nextIndex > 0);
++        }
++
++        public E previous() {
++            checkModCount();
++            if (!hasPrevious()) {
++                throw new NoSuchElementException("Already at start of list.");
++            }
++            if (next == null) {
++                next = parent.root.get(nextIndex - 1);
++            } else {
++                next = next.previous();
++            }
++            E value = next.getValue();
++            current = next;
++            currentIndex = --nextIndex;
++            return value;
++        }
++
++        public int nextIndex() {
++            return nextIndex;
++        }
++
++        public int previousIndex() {
++            return nextIndex() - 1;
++        }
++
++        public void remove() {
++            checkModCount();
++            if (current == null) {
++                throw new IllegalStateException();
++            }
++            parent.remove(currentIndex);
++            current = null;
++            currentIndex = -1;
++            nextIndex--;
++            expectedModCount++;
++        }
++
++        public void set(E obj) {
++            checkModCount();
++            if (current == null) {
++                throw new IllegalStateException();
++            }
++            current.setValue(obj);
++        }
++
++        public void add(E obj) {
++            checkModCount();
++            parent.add(nextIndex, obj);
++            current = null;
++            currentIndex = -1;
++            nextIndex++;
++            expectedModCount++;
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/TypedList.java
+@@ -0,0 +1,60 @@
++// GenericsNote: deprecated and useless
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import org.apache.commons.collections15.functors.InstanceofPredicate;
++
++import java.util.List;
++
++/**
++ * Decorates another <code>List</code> to validate that elements
++ * added are of a specific type.
++ * <p/>
++ * The validation of additions is performed via an instanceof test against
++ * a specified <code>Class</code>. If an object cannot be added to the
++ * collection, an IllegalArgumentException is thrown.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ * @deprecated Java Generics makes this class obsolete.
++ */
++public class TypedList {
++
++    /**
++     * Factory method to create a typed list.
++     * <p/>
++     * If there are any elements already in the list being decorated, they
++     * are validated.
++     *
++     * @param list the list to decorate, must not be null
++     * @param type the type to allow into the collection, must not be null
++     * @throws IllegalArgumentException if list or type is null
++     * @throws IllegalArgumentException if the list contains invalid elements
++     */
++    public static List decorate(List list, Class type) {
++        return new PredicatedList(list, InstanceofPredicate.getInstance(type));
++    }
++
++    /**
++     * Restrictive constructor.
++     */
++    protected TypedList() {
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/UnmodifiableList.java
+@@ -0,0 +1,127 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.list;
++
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.iterators.UnmodifiableIterator;
++import org.apache.commons.collections15.iterators.UnmodifiableListIterator;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.List;
++import java.util.ListIterator;
++
++/**
++ * Decorates another <code>List</code> to ensure it can't be altered.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableList <E> extends AbstractSerializableListDecorator<E> implements Unmodifiable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 6595182819922443652L;
++
++    /**
++     * Factory method to create an unmodifiable list.
++     *
++     * @param list the list to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    public static <E> List<E> decorate(List<E> list) {
++        if (list instanceof Unmodifiable) {
++            return list;
++        }
++        return new UnmodifiableList<E>(list);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param list the list to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    private UnmodifiableList(List<E> list) {
++        super(list);
++    }
++
++    //-----------------------------------------------------------------------
++    public Iterator<E> iterator() {
++        return UnmodifiableIterator.decorate(getCollection().iterator());
++    }
++
++    public boolean add(E object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean remove(Object object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    //-----------------------------------------------------------------------
++    public ListIterator<E> listIterator() {
++        return UnmodifiableListIterator.decorate(getList().listIterator());
++    }
++
++    public ListIterator<E> listIterator(int index) {
++        return UnmodifiableListIterator.decorate(getList().listIterator(index));
++    }
++
++    public void add(int index, E object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean addAll(int index, Collection<? extends E> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public E remove(int index) {
++        throw new UnsupportedOperationException();
++    }
++
++    public E set(int index, E object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public List<E> subList(int fromIndex, int toIndex) {
++        List<E> sub = getList().subList(fromIndex, toIndex);
++        return new UnmodifiableList<E>(sub);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/list/package.html
+@@ -0,0 +1,41 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:32 pents90 Exp $ -->
++ <!--
++   Copyright 2003-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<BODY>
++<p>
++This package contains implementations of the
++{@link java.util.List List} interface.
++<p>
++The following implementations are provided in the package:
++<ul>
++<li>TreeList - a list that is optimised for insertions and removals at any index in the list
++<li>CursorableLinkedList - a list that can be modified while it's listIterator (cursor) is being used
++<li>NodeCachingLinkedList - a linked list that caches the storage nodes for a performance gain
++</ul>
++<p>
++The following decorators are provided in the package:
++<ul>
++<li>Synchronized - synchronizes method access for multi-threaded environments
++<li>Unmodifiable - ensures the collection cannot be altered
++<li>Predicated - ensures that only elements that are valid according to a predicate can be added
++<li>Typed - ensures that only elements that are of a specific type can be added
++<li>Transformed - transforms each element added
++<li>FixedSize - ensures that the size of the list cannot change
++<li>Lazy - creates objects in the list on demand
++<li>SetUnique - a list that avoids duplicate entries like a Set
++</ul>
++</pre>
++</BODY>
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/AbstractHashedMap.java
+@@ -0,0 +1,1344 @@
++// GenericsNote: Converted -- However, null keys will now be represented in the internal structures, a big change.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.IterableMap;
++import org.apache.commons.collections15.KeyValue;
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.iterators.EmptyIterator;
++import org.apache.commons.collections15.iterators.EmptyMapIterator;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.util.*;
++
++/**
++ * An abstract implementation of a hash-based map which provides numerous points for
++ * subclasses to override.
++ * <p/>
++ * This class implements all the features necessary for a subclass hash-based map.
++ * Key-value entries are stored in instances of the <code>HashEntry</code> class,
++ * which can be overridden and replaced. The iterators can similarly be replaced,
++ * without the need to replace the KeySet, EntrySet and Values view classes.
++ * <p/>
++ * Overridable methods are provided to change the default hashing behaviour, and
++ * to change how entries are added to and removed from the map. Hopefully, all you
++ * need for unusual subclasses is here.
++ * <p/>
++ * NOTE: From Commons Collections 3.1 this class extends AbstractMap.
++ * This is to provide backwards compatibility for ReferenceMap between v3.0 and v3.1.
++ * This extends clause will be removed in v4.0.
++ *
++ * @author java util HashMap
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class AbstractHashedMap <K,V> extends AbstractMap<K, V> implements IterableMap<K, V> {
++
++    protected static final String NO_NEXT_ENTRY = "No next() entry in the iteration";
++    protected static final String NO_PREVIOUS_ENTRY = "No previous() entry in the iteration";
++    protected static final String REMOVE_INVALID = "remove() can only be called once after next()";
++    protected static final String GETKEY_INVALID = "getKey() can only be called after next() and before remove()";
++    protected static final String GETVALUE_INVALID = "getValue() can only be called after next() and before remove()";
++    protected static final String SETVALUE_INVALID = "setValue() can only be called after next() and before remove()";
++
++    /**
++     * The default capacity to use
++     */
++    protected static final int DEFAULT_CAPACITY = 16;
++    /**
++     * The default threshold to use
++     */
++    protected static final int DEFAULT_THRESHOLD = 12;
++    /**
++     * The default load factor to use
++     */
++    protected static final float DEFAULT_LOAD_FACTOR = 0.75f;
++    /**
++     * The maximum capacity allowed
++     */
++    protected static final int MAXIMUM_CAPACITY = 1 << 30;
++    /**
++     * An object for masking null
++     */
++    protected static final Object NULL = new Object();
++
++    /**
++     * Load factor, normally 0.75
++     */
++    protected transient float loadFactor;
++    /**
++     * The size of the map
++     */
++    protected transient int size;
++    /**
++     * Map entries
++     */
++    protected transient HashEntry<K, V>[] data;
++    /**
++     * Size at which to rehash
++     */
++    protected transient int threshold;
++    /**
++     * Modification count for iterators
++     */
++    protected transient int modCount;
++    /**
++     * Entry set
++     */
++    protected transient EntrySet<K, V> entrySet;
++    /**
++     * Key set
++     */
++    protected transient KeySet<K, V> keySet;
++    /**
++     * Values
++     */
++    protected transient Values<K, V> values;
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     */
++    protected AbstractHashedMap() {
++        super();
++    }
++
++    /**
++     * Constructor which performs no validation on the passed in parameters.
++     *
++     * @param initialCapacity the initial capacity, must be a power of two
++     * @param loadFactor      the load factor, must be > 0.0f and generally < 1.0f
++     * @param threshold       the threshold, must be sensible
++     */
++    protected AbstractHashedMap(int initialCapacity, float loadFactor, int threshold) {
++        super();
++        this.loadFactor = loadFactor;
++        this.data = new HashEntry[initialCapacity];
++        this.threshold = threshold;
++        init();
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity and
++     * default load factor.
++     *
++     * @param initialCapacity the initial capacity
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     */
++    protected AbstractHashedMap(int initialCapacity) {
++        this(initialCapacity, DEFAULT_LOAD_FACTOR);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity and
++     * load factor.
++     *
++     * @param initialCapacity the initial capacity
++     * @param loadFactor      the load factor
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     * @throws IllegalArgumentException if the load factor is less than or equal to zero
++     */
++    protected AbstractHashedMap(int initialCapacity, float loadFactor) {
++        super();
++        if (initialCapacity < 1) {
++            throw new IllegalArgumentException("Initial capacity must be greater than 0");
++        }
++        if (loadFactor <= 0.0f || Float.isNaN(loadFactor)) {
++            throw new IllegalArgumentException("Load factor must be greater than 0");
++        }
++        this.loadFactor = loadFactor;
++        this.threshold = calculateThreshold(initialCapacity, loadFactor);
++        initialCapacity = calculateNewCapacity(initialCapacity);
++        this.data = new HashEntry[initialCapacity];
++        init();
++    }
++
++    /**
++     * Constructor copying elements from another map.
++     *
++     * @param map the map to copy
++     * @throws NullPointerException if the map is null
++     */
++    protected AbstractHashedMap(Map<? extends K, ? extends V> map) {
++        this(Math.max(2 * map.size(), DEFAULT_CAPACITY), DEFAULT_LOAD_FACTOR);
++        putAll(map);
++    }
++
++    /**
++     * Initialise subclasses during construction, cloning or deserialization.
++     */
++    protected void init() {
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the value mapped to the key specified.
++     *
++     * @param key the key
++     * @return the mapped value, null if no match
++     */
++    public V get(Object key) {
++        int hashCode = hash((key == null) ? NULL : key);
++        HashEntry<K, V> entry = data[hashIndex(hashCode, data.length)]; // no local for hash index
++        while (entry != null) {
++            if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) {
++                return entry.getValue();
++            }
++            entry = entry.next;
++        }
++        return null;
++    }
++
++    /**
++     * Gets the size of the map.
++     *
++     * @return the size
++     */
++    public int size() {
++        return size;
++    }
++
++    /**
++     * Checks whether the map is currently empty.
++     *
++     * @return true if the map is currently size zero
++     */
++    public boolean isEmpty() {
++        return (size == 0);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Checks whether the map contains the specified key.
++     *
++     * @param key the key to search for
++     * @return true if the map contains the key
++     */
++    public boolean containsKey(Object key) {
++        int hashCode = hash((key == null) ? NULL : key);
++        HashEntry entry = data[hashIndex(hashCode, data.length)]; // no local for hash index
++        while (entry != null) {
++            if (entry.hashCode == hashCode && isEqualKey(key, entry.getKey())) {
++                return true;
++            }
++            entry = entry.next;
++        }
++        return false;
++    }
++
++    /**
++     * Checks whether the map contains the specified value.
++     *
++     * @param value the value to search for
++     * @return true if the map contains the value
++     */
++    public boolean containsValue(Object value) {
++        if (value == null) {
++            for (int i = 0, isize = data.length; i < isize; i++) {
++                HashEntry entry = data[i];
++                while (entry != null) {
++                    if (entry.getValue() == null) {
++                        return true;
++                    }
++                    entry = entry.next;
++                }
++            }
++        } else {
++            for (int i = 0, isize = data.length; i < isize; i++) {
++                HashEntry entry = data[i];
++                while (entry != null) {
++                    if (isEqualValue(value, entry.getValue())) {
++                        return true;
++                    }
++                    entry = entry.next;
++                }
++            }
++        }
++        return false;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Puts a key-value mapping into this map.
++     *
++     * @param key   the key to add
++     * @param value the value to add
++     * @return the value previously mapped to this key, null if none
++     */
++    public V put(K key, V value) {
++        int hashCode = hash((key == null) ? NULL : key);
++        int index = hashIndex(hashCode, data.length);
++        HashEntry<K, V> entry = data[index];
++        while (entry != null) {
++            if (entry.hashCode == hashCode && isEqualKey(key, entry.getKey())) {
++                V oldValue = entry.getValue();
++                updateEntry(entry, value);
++                return oldValue;
++            }
++            entry = entry.next;
++        }
++        addMapping(index, hashCode, key, value);
++        return null;
++    }
++
++    /**
++     * Puts all the values from the specified map into this map.
++     * <p/>
++     * This implementation iterates around the specified map and
++     * uses {@link #put(Object, Object)}.
++     *
++     * @param map the map to add
++     * @throws NullPointerException if the map is null
++     */
++    public void putAll(Map<? extends K, ? extends V> map) {
++        int mapSize = map.size();
++        if (mapSize == 0) {
++            return;
++        }
++        int newSize = (int) ((size + mapSize) / loadFactor + 1);
++        ensureCapacity(calculateNewCapacity(newSize));
++        // Have to cast here because of compiler inference problems.
++        for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
++            Map.Entry<? extends K, ? extends V> entry = (Map.Entry<? extends K, ? extends V>) it.next();
++            put(entry.getKey(), entry.getValue());
++        }
++    }
++
++    /**
++     * Removes the specified mapping from this map.
++     *
++     * @param key the mapping to remove
++     * @return the value mapped to the removed key, null if key not in map
++     */
++    public V remove(Object key) {
++        int hashCode = hash((key == null) ? NULL : key);
++        int index = hashIndex(hashCode, data.length);
++        HashEntry<K, V> entry = data[index];
++        HashEntry<K, V> previous = null;
++        while (entry != null) {
++            if (entry.hashCode == hashCode && isEqualKey(key, entry.getKey())) {
++                V oldValue = entry.getValue();
++                removeMapping(entry, index, previous);
++                return oldValue;
++            }
++            previous = entry;
++            entry = entry.next;
++        }
++        return null;
++    }
++
++    /**
++     * Clears the map, resetting the size to zero and nullifying references
++     * to avoid garbage collection issues.
++     */
++    public void clear() {
++        modCount++;
++        HashEntry[] data = this.data;
++        for (int i = data.length - 1; i >= 0; i--) {
++            data[i] = null;
++        }
++        size = 0;
++    }
++
++    /**
++     * Gets the hash code for the key specified.
++     * This implementation uses the additional hashing routine from JDK1.4.
++     * Subclasses can override this to return alternate hash codes.
++     *
++     * @param key the key to get a hash code for
++     * @return the hash code
++     */
++    protected int hash(Object key) {
++        // same as JDK 1.4
++        int h = key.hashCode();
++        h += ~(h << 9);
++        h ^= (h >>> 14);
++        h += (h << 4);
++        h ^= (h >>> 10);
++        return h;
++    }
++
++    /**
++     * Compares two keys, in internal converted form, to see if they are equal.
++     * This implementation uses the equals method.
++     * Subclasses can override this to match differently.
++     *
++     * @param key1 the first key to compare passed in from outside
++     * @param key2 the second key extracted from the entry via <code>entry.key</code>
++     * @return true if equal
++     */
++    protected boolean isEqualKey(Object key1, Object key2) {
++        return (key1 == key2 || ((key1 != null) && key1.equals(key2)));
++    }
++
++    /**
++     * Compares two values, in external form, to see if they are equal.
++     * This implementation uses the equals method and assumes neither value is null.
++     * Subclasses can override this to match differently.
++     *
++     * @param value1 the first value to compare passed in from outside
++     * @param value2 the second value extracted from the entry via <code>getValue()</code>
++     * @return true if equal
++     */
++    protected boolean isEqualValue(Object value1, Object value2) {
++        return (value1 == value2 || value1.equals(value2));
++    }
++
++    /**
++     * Gets the index into the data storage for the hashCode specified.
++     * This implementation uses the least significant bits of the hashCode.
++     * Subclasses can override this to return alternate bucketing.
++     *
++     * @param hashCode the hash code to use
++     * @param dataSize the size of the data to pick a bucket from
++     * @return the bucket index
++     */
++    protected int hashIndex(int hashCode, int dataSize) {
++        return hashCode & (dataSize - 1);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the entry mapped to the key specified.
++     * <p/>
++     * This method exists for subclasses that may need to perform a multi-step
++     * process accessing the entry. The public methods in this class don't use this
++     * method to gain a small performance boost.
++     *
++     * @param key the key
++     * @return the entry, null if no match
++     */
++    protected HashEntry<K, V> getEntry(Object key) {
++        int hashCode = hash((key == null) ? NULL : key);
++        HashEntry<K, V> entry = data[hashIndex(hashCode, data.length)]; // no local for hash index
++        while (entry != null) {
++            if (entry.hashCode == hashCode && isEqualKey(key, entry.getKey())) {
++                return entry;
++            }
++            entry = entry.next;
++        }
++        return null;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Updates an existing key-value mapping to change the value.
++     * <p/>
++     * This implementation calls <code>setValue()</code> on the entry.
++     * Subclasses could override to handle changes to the map.
++     *
++     * @param entry    the entry to update
++     * @param newValue the new value to store
++     */
++    protected void updateEntry(HashEntry<K, V> entry, V newValue) {
++        entry.setValue(newValue);
++    }
++
++    /**
++     * Reuses an existing key-value mapping, storing completely new data.
++     * <p/>
++     * This implementation sets all the data fields on the entry.
++     * Subclasses could populate additional entry fields.
++     *
++     * @param entry     the entry to update, not null
++     * @param hashIndex the index in the data array
++     * @param hashCode  the hash code of the key to add
++     * @param key       the key to add
++     * @param value     the value to add
++     */
++    protected void reuseEntry(HashEntry<K, V> entry, int hashIndex, int hashCode, K key, V value) {
++        entry.next = data[hashIndex];
++        entry.hashCode = hashCode;
++        entry.key = key;
++        entry.value = value;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Adds a new key-value mapping into this map.
++     * <p/>
++     * This implementation calls <code>createEntry()</code>, <code>addEntry()</code>
++     * and <code>checkCapacity()</code>.
++     * It also handles changes to <code>modCount</code> and <code>size</code>.
++     * Subclasses could override to fully control adds to the map.
++     *
++     * @param hashIndex the index into the data array to store at
++     * @param hashCode  the hash code of the key to add
++     * @param key       the key to add
++     * @param value     the value to add
++     */
++    protected void addMapping(int hashIndex, int hashCode, K key, V value) {
++        modCount++;
++        HashEntry<K, V> entry = createEntry(data[hashIndex], hashCode, key, value);
++        addEntry(entry, hashIndex);
++        size++;
++        checkCapacity();
++    }
++
++    /**
++     * Creates an entry to store the key-value data.
++     * <p/>
++     * This implementation creates a new HashEntry instance.
++     * Subclasses can override this to return a different storage class,
++     * or implement caching.
++     *
++     * @param next     the next entry in sequence
++     * @param hashCode the hash code to use
++     * @param key      the key to store
++     * @param value    the value to store
++     * @return the newly created entry
++     */
++    protected HashEntry<K, V> createEntry(HashEntry<K, V> next, int hashCode, K key, V value) {
++        return new HashEntry<K, V>(next, hashCode, key, value);
++    }
++
++    /**
++     * Adds an entry into this map.
++     * <p/>
++     * This implementation adds the entry to the data storage table.
++     * Subclasses could override to handle changes to the map.
++     *
++     * @param entry     the entry to add
++     * @param hashIndex the index into the data array to store at
++     */
++    protected void addEntry(HashEntry<K, V> entry, int hashIndex) {
++        data[hashIndex] = entry;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Removes a mapping from the map.
++     * <p/>
++     * This implementation calls <code>removeEntry()</code> and <code>destroyEntry()</code>.
++     * It also handles changes to <code>modCount</code> and <code>size</code>.
++     * Subclasses could override to fully control removals from the map.
++     *
++     * @param entry     the entry to remove
++     * @param hashIndex the index into the data structure
++     * @param previous  the previous entry in the chain
++     */
++    protected void removeMapping(HashEntry<K, V> entry, int hashIndex, HashEntry<K, V> previous) {
++        modCount++;
++        removeEntry(entry, hashIndex, previous);
++        size--;
++        destroyEntry(entry);
++    }
++
++    /**
++     * Removes an entry from the chain stored in a particular index.
++     * <p/>
++     * This implementation removes the entry from the data storage table.
++     * The size is not updated.
++     * Subclasses could override to handle changes to the map.
++     *
++     * @param entry     the entry to remove
++     * @param hashIndex the index into the data structure
++     * @param previous  the previous entry in the chain
++     */
++    protected void removeEntry(HashEntry<K, V> entry, int hashIndex, HashEntry<K, V> previous) {
++        if (previous == null) {
++            data[hashIndex] = entry.next;
++        } else {
++            previous.next = entry.next;
++        }
++    }
++
++    /**
++     * Kills an entry ready for the garbage collector.
++     * <p/>
++     * This implementation prepares the HashEntry for garbage collection.
++     * Subclasses can override this to implement caching (override clear as well).
++     *
++     * @param entry the entry to destroy
++     */
++    protected void destroyEntry(HashEntry<K, V> entry) {
++        entry.next = null;
++        entry.key = null;
++        entry.value = null;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Checks the capacity of the map and enlarges it if necessary.
++     * <p/>
++     * This implementation uses the threshold to check if the map needs enlarging
++     */
++    protected void checkCapacity() {
++        if (size >= threshold) {
++            int newCapacity = data.length * 2;
++            if (newCapacity <= MAXIMUM_CAPACITY) {
++                ensureCapacity(newCapacity);
++            }
++        }
++    }
++
++    /**
++     * Changes the size of the data structure to the capacity proposed.
++     *
++     * @param newCapacity the new capacity of the array (a power of two, less or equal to max)
++     */
++    protected void ensureCapacity(int newCapacity) {
++        int oldCapacity = data.length;
++        if (newCapacity <= oldCapacity) {
++            return;
++        }
++        if (size == 0) {
++            threshold = calculateThreshold(newCapacity, loadFactor);
++            data = new HashEntry[newCapacity];
++        } else {
++            HashEntry<K, V> oldEntries[] = data;
++            HashEntry<K, V> newEntries[] = new HashEntry[newCapacity];
++
++            modCount++;
++            for (int i = oldCapacity - 1; i >= 0; i--) {
++                HashEntry<K, V> entry = oldEntries[i];
++                if (entry != null) {
++                    oldEntries[i] = null;  // gc
++                    do {
++                        HashEntry<K, V> next = entry.next;
++                        int index = hashIndex(entry.hashCode, newCapacity);
++                        entry.next = newEntries[index];
++                        newEntries[index] = entry;
++                        entry = next;
++                    } while (entry != null);
++                }
++            }
++            threshold = calculateThreshold(newCapacity, loadFactor);
++            data = newEntries;
++        }
++    }
++
++    /**
++     * Calculates the new capacity of the map.
++     * This implementation normalizes the capacity to a power of two.
++     *
++     * @param proposedCapacity the proposed capacity
++     * @return the normalized new capacity
++     */
++    protected int calculateNewCapacity(int proposedCapacity) {
++        int newCapacity = 1;
++        if (proposedCapacity > MAXIMUM_CAPACITY) {
++            newCapacity = MAXIMUM_CAPACITY;
++        } else {
++            while (newCapacity < proposedCapacity) {
++                newCapacity <<= 1;  // multiply by two
++            }
++            if (newCapacity > MAXIMUM_CAPACITY) {
++                newCapacity = MAXIMUM_CAPACITY;
++            }
++        }
++        return newCapacity;
++    }
++
++    /**
++     * Calculates the new threshold of the map, where it will be resized.
++     * This implementation uses the load factor.
++     *
++     * @param newCapacity the new capacity
++     * @param factor      the load factor
++     * @return the new resize threshold
++     */
++    protected int calculateThreshold(int newCapacity, float factor) {
++        return (int) (newCapacity * factor);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the <code>next</code> field from a <code>HashEntry</code>.
++     * Used in subclasses that have no visibility of the field.
++     *
++     * @param entry the entry to query, must not be null
++     * @return the <code>next</code> field of the entry
++     * @throws NullPointerException if the entry is null
++     * @since Commons Collections 3.1
++     */
++    protected HashEntry<K, V> entryNext(HashEntry<K, V> entry) {
++        return entry.next;
++    }
++
++    /**
++     * Gets the <code>hashCode</code> field from a <code>HashEntry</code>.
++     * Used in subclasses that have no visibility of the field.
++     *
++     * @param entry the entry to query, must not be null
++     * @return the <code>hashCode</code> field of the entry
++     * @throws NullPointerException if the entry is null
++     * @since Commons Collections 3.1
++     */
++    protected int entryHashCode(HashEntry<K, V> entry) {
++        return entry.hashCode;
++    }
++
++    /**
++     * Gets the <code>key</code> field from a <code>HashEntry</code>.
++     * Used in subclasses that have no visibility of the field.
++     *
++     * @param entry the entry to query, must not be null
++     * @return the <code>key</code> field of the entry
++     * @throws NullPointerException if the entry is null
++     * @since Commons Collections 3.1
++     */
++    protected K entryKey(HashEntry<K, V> entry) {
++        return entry.key;
++    }
++
++    /**
++     * Gets the <code>value</code> field from a <code>HashEntry</code>.
++     * Used in subclasses that have no visibility of the field.
++     *
++     * @param entry the entry to query, must not be null
++     * @return the <code>value</code> field of the entry
++     * @throws NullPointerException if the entry is null
++     * @since Commons Collections 3.1
++     */
++    protected V entryValue(HashEntry<K, V> entry) {
++        return entry.value;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator over the map.
++     * Changes made to the iterator affect this map.
++     * <p/>
++     * A MapIterator returns the keys in the map. It also provides convenient
++     * methods to get the key and value, and set the value.
++     * It avoids the need to create an entrySet/keySet/values object.
++     * It also avoids creating the Map.Entry object.
++     *
++     * @return the map iterator
++     */
++    public MapIterator<K, V> mapIterator() {
++        if (size == 0) {
++            return EmptyMapIterator.INSTANCE;
++        }
++        return new HashMapIterator<K, V>(this);
++    }
++
++    /**
++     * MapIterator implementation.
++     */
++    protected static class HashMapIterator <K,V> extends HashIterator<K, V> implements MapIterator<K, V> {
++
++        protected HashMapIterator(AbstractHashedMap<K, V> parent) {
++            super(parent);
++        }
++
++        public K next() {
++            return super.nextEntry().getKey();
++        }
++
++        public K getKey() {
++            HashEntry<K, V> current = currentEntry();
++            if (current == null) {
++                throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
++            }
++            return current.getKey();
++        }
++
++        public V getValue() {
++            HashEntry<K, V> current = currentEntry();
++            if (current == null) {
++                throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
++            }
++            return current.getValue();
++        }
++
++        public V setValue(V value) {
++            HashEntry<K, V> current = currentEntry();
++            if (current == null) {
++                throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
++            }
++            return current.setValue(value);
++        }
++    }
++    
++    //-----------------------------------------------------------------------    
++    /**
++     * Gets the entrySet view of the map.
++     * Changes made to the view affect this map.
++     * To simply iterate through the entries, use {@link #mapIterator()}.
++     *
++     * @return the entrySet view
++     */
++    public Set<Map.Entry<K, V>> entrySet() {
++        if (entrySet == null) {
++            entrySet = new EntrySet<K, V>(this);
++        }
++        return entrySet;
++    }
++
++    /**
++     * Creates an entry set iterator.
++     * Subclasses can override this to return iterators with different properties.
++     *
++     * @return the entrySet iterator
++     */
++    protected Iterator<Map.Entry<K, V>> createEntrySetIterator() {
++        if (size() == 0) {
++            return EmptyIterator.INSTANCE;
++        }
++        return new EntrySetIterator<K, V>(this);
++    }
++
++    /**
++     * EntrySet implementation.
++     */
++    protected static class EntrySet <K,V> extends AbstractSet<Map.Entry<K, V>> {
++        /**
++         * The parent map
++         */
++        protected final AbstractHashedMap<K, V> parent;
++
++        protected EntrySet(AbstractHashedMap<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public int size() {
++            return parent.size();
++        }
++
++        public void clear() {
++            parent.clear();
++        }
++
++        public boolean contains(Map.Entry<K, V> entry) {
++            Map.Entry<K, V> e = entry;
++            Entry<K, V> match = parent.getEntry(e.getKey());
++            return (match != null && match.equals(e));
++        }
++
++        public boolean remove(Object obj) {
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++            if (contains(obj) == false) {
++                return false;
++            }
++            Map.Entry<K, V> entry = (Map.Entry<K, V>) obj;
++            K key = entry.getKey();
++            parent.remove(key);
++            return true;
++        }
++
++        public Iterator<Map.Entry<K, V>> iterator() {
++            return parent.createEntrySetIterator();
++        }
++    }
++
++    /**
++     * EntrySet iterator.
++     */
++    protected static class EntrySetIterator <K,V> extends HashIterator<K, V> implements Iterator<Map.Entry<K, V>> {
++
++        protected EntrySetIterator(AbstractHashedMap<K, V> parent) {
++            super(parent);
++        }
++
++        public HashEntry<K, V> next() {
++            return super.nextEntry();
++        }
++    }
++
++    //-----------------------------------------------------------------------    
++    /**
++     * Gets the keySet view of the map.
++     * Changes made to the view affect this map.
++     * To simply iterate through the keys, use {@link #mapIterator()}.
++     *
++     * @return the keySet view
++     */
++    public Set<K> keySet() {
++        if (keySet == null) {
++            keySet = new KeySet<K, V>(this);
++        }
++        return keySet;
++    }
++
++    /**
++     * Creates a key set iterator.
++     * Subclasses can override this to return iterators with different properties.
++     *
++     * @return the keySet iterator
++     */
++    protected Iterator<K> createKeySetIterator() {
++        if (size() == 0) {
++            return EmptyIterator.INSTANCE;
++        }
++        return new KeySetIterator<K, V>(this);
++    }
++
++    /**
++     * KeySet implementation.
++     */
++    protected static class KeySet <K,V> extends AbstractSet<K> {
++        /**
++         * The parent map
++         */
++        protected final AbstractHashedMap<K, V> parent;
++
++        protected KeySet(AbstractHashedMap<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public int size() {
++            return parent.size();
++        }
++
++        public void clear() {
++            parent.clear();
++        }
++
++        public boolean contains(Object key) {
++            return parent.containsKey(key);
++        }
++
++        public boolean remove(Object key) {
++            boolean result = parent.containsKey(key);
++            parent.remove(key);
++            return result;
++        }
++
++        public Iterator<K> iterator() {
++            return parent.createKeySetIterator();
++        }
++    }
++
++    /**
++     * KeySet iterator.
++     */
++    protected static class KeySetIterator <K,V> extends HashIterator<K, V> implements Iterator<K> {
++
++        protected KeySetIterator(AbstractHashedMap<K, V> parent) {
++            super(parent);
++        }
++
++        public K next() {
++            return super.nextEntry().getKey();
++        }
++    }
++    
++    //-----------------------------------------------------------------------    
++    /**
++     * Gets the values view of the map.
++     * Changes made to the view affect this map.
++     * To simply iterate through the values, use {@link #mapIterator()}.
++     *
++     * @return the values view
++     */
++    public Collection<V> values() {
++        if (values == null) {
++            values = new Values(this);
++        }
++        return values;
++    }
++
++    /**
++     * Creates a values iterator.
++     * Subclasses can override this to return iterators with different properties.
++     *
++     * @return the values iterator
++     */
++    protected Iterator<V> createValuesIterator() {
++        if (size() == 0) {
++            return EmptyIterator.INSTANCE;
++        }
++        return new ValuesIterator<K, V>(this);
++    }
++
++    /**
++     * Values implementation.
++     */
++    protected static class Values <K,V> extends AbstractCollection<V> {
++        /**
++         * The parent map
++         */
++        protected final AbstractHashedMap<K, V> parent;
++
++        protected Values(AbstractHashedMap<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public int size() {
++            return parent.size();
++        }
++
++        public void clear() {
++            parent.clear();
++        }
++
++        public boolean contains(Object value) {
++            return parent.containsValue(value);
++        }
++
++        public Iterator<V> iterator() {
++            return parent.createValuesIterator();
++        }
++    }
++
++    /**
++     * Values iterator.
++     */
++    protected static class ValuesIterator <K,V> extends HashIterator<K, V> implements Iterator<V> {
++
++        protected ValuesIterator(AbstractHashedMap<K, V> parent) {
++            super(parent);
++        }
++
++        public V next() {
++            return super.nextEntry().getValue();
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * HashEntry used to store the data.
++     * <p/>
++     * If you subclass <code>AbstractHashedMap</code> but not <code>HashEntry</code>
++     * then you will not be able to access the protected fields.
++     * The <code>entryXxx()</code> methods on <code>AbstractHashedMap</code> exist
++     * to provide the necessary access.
++     */
++    protected static class HashEntry <K,V> implements Map.Entry<K, V>, KeyValue<K, V> {
++        /**
++         * The next entry in the hash chain
++         */
++        protected HashEntry<K, V> next;
++        /**
++         * The hash code of the key
++         */
++        protected int hashCode;
++        /**
++         * The key
++         */
++        private K key;
++        /**
++         * The value
++         */
++        private V value;
++
++        protected HashEntry(HashEntry<K, V> next, int hashCode, K key, V value) {
++            super();
++            this.next = next;
++            this.hashCode = hashCode;
++            this.key = key;
++            this.value = value;
++        }
++
++        public K getKey() {
++            return key;
++        }
++
++        public void setKey(K key) {
++            this.key = key;
++        }
++
++        public V getValue() {
++            return value;
++        }
++
++        public V setValue(V value) {
++            V old = this.value;
++            this.value = value;
++            return old;
++        }
++
++        public boolean equals(Object obj) {
++            if (obj == this) {
++                return true;
++            }
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++            Map.Entry other = (Map.Entry) obj;
++            return (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) && (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue()));
++        }
++
++        public int hashCode() {
++            return (getKey() == null ? 0 : getKey().hashCode()) ^ (getValue() == null ? 0 : getValue().hashCode());
++        }
++
++        public String toString() {
++            return new StringBuffer().append(getKey()).append('=').append(getValue()).toString();
++        }
++    }
++
++    /**
++     * Base Iterator
++     */
++    protected static abstract class HashIterator <K,V> {
++
++        /**
++         * The parent map
++         */
++        protected final AbstractHashedMap parent;
++        /**
++         * The current index into the array of buckets
++         */
++        protected int hashIndex;
++        /**
++         * The last returned entry
++         */
++        protected HashEntry<K, V> last;
++        /**
++         * The next entry
++         */
++        protected HashEntry<K, V> next;
++        /**
++         * The modification count expected
++         */
++        protected int expectedModCount;
++
++        protected HashIterator(AbstractHashedMap<K, V> parent) {
++            super();
++            this.parent = parent;
++            HashEntry<K, V>[] data = parent.data;
++            int i = data.length;
++            HashEntry<K, V> next = null;
++            while (i > 0 && next == null) {
++                next = data[--i];
++            }
++            this.next = next;
++            this.hashIndex = i;
++            this.expectedModCount = parent.modCount;
++        }
++
++        public boolean hasNext() {
++            return (next != null);
++        }
++
++        protected HashEntry<K, V> nextEntry() {
++            if (parent.modCount != expectedModCount) {
++                throw new ConcurrentModificationException();
++            }
++            HashEntry<K, V> newCurrent = next;
++            if (newCurrent == null) {
++                throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
++            }
++            HashEntry<K, V>[] data = parent.data;
++            int i = hashIndex;
++            HashEntry<K, V> n = newCurrent.next;
++            while (n == null && i > 0) {
++                n = data[--i];
++            }
++            next = n;
++            hashIndex = i;
++            last = newCurrent;
++            return newCurrent;
++        }
++
++        protected HashEntry<K, V> currentEntry() {
++            return last;
++        }
++
++        public void remove() {
++            if (last == null) {
++                throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
++            }
++            if (parent.modCount != expectedModCount) {
++                throw new ConcurrentModificationException();
++            }
++            parent.remove(last.getKey());
++            last = null;
++            expectedModCount = parent.modCount;
++        }
++
++        public String toString() {
++            if (last != null) {
++                return "Iterator[" + last.getKey() + "=" + last.getValue() + "]";
++            } else {
++                return "Iterator[]";
++            }
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Writes the map data to the stream. This method must be overridden if a
++     * subclass must be setup before <code>put()</code> is used.
++     * <p/>
++     * Serialization is not one of the JDK's nicest topics. Normal serialization will
++     * initialise the superclass before the subclass. Sometimes however, this isn't
++     * what you want, as in this case the <code>put()</code> method on read can be
++     * affected by subclass state.
++     * <p/>
++     * The solution adopted here is to serialize the state data of this class in
++     * this protected method. This method must be called by the
++     * <code>writeObject()</code> of the first serializable subclass.
++     * <p/>
++     * Subclasses may override if they have a specific field that must be present
++     * on read before this implementation will work. Generally, the read determines
++     * what must be serialized here, if anything.
++     *
++     * @param out the output stream
++     */
++    protected void doWriteObject(ObjectOutputStream out) throws IOException {
++        out.writeFloat(loadFactor);
++        out.writeInt(data.length);
++        out.writeInt(size);
++        for (MapIterator it = mapIterator(); it.hasNext();) {
++            out.writeObject(it.next());
++            out.writeObject(it.getValue());
++        }
++    }
++
++    /**
++     * Reads the map data from the stream. This method must be overridden if a
++     * subclass must be setup before <code>put()</code> is used.
++     * <p/>
++     * Serialization is not one of the JDK's nicest topics. Normal serialization will
++     * initialise the superclass before the subclass. Sometimes however, this isn't
++     * what you want, as in this case the <code>put()</code> method on read can be
++     * affected by subclass state.
++     * <p/>
++     * The solution adopted here is to deserialize the state data of this class in
++     * this protected method. This method must be called by the
++     * <code>readObject()</code> of the first serializable subclass.
++     * <p/>
++     * Subclasses may override if the subclass has a specific field that must be present
++     * before <code>put()</code> or <code>calculateThreshold()</code> will work correctly.
++     *
++     * @param in the input stream
++     */
++    protected void doReadObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        loadFactor = in.readFloat();
++        int capacity = in.readInt();
++        int size = in.readInt();
++        init();
++        data = new HashEntry[capacity];
++        for (int i = 0; i < size; i++) {
++            K key = (K) in.readObject();
++            V value = (V) in.readObject();
++            put(key, value);
++        }
++        threshold = calculateThreshold(data.length, loadFactor);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Clones the map without cloning the keys or values.
++     * <p/>
++     * To implement <code>clone()</code>, a subclass must implement the
++     * <code>Cloneable</code> interface and make this method public.
++     *
++     * @return a shallow clone
++     */
++    protected Object clone() {
++        try {
++            AbstractHashedMap cloned = (AbstractHashedMap) super.clone();
++            cloned.data = new HashEntry[data.length];
++            cloned.entrySet = null;
++            cloned.keySet = null;
++            cloned.values = null;
++            cloned.modCount = 0;
++            cloned.size = 0;
++            cloned.init();
++            cloned.putAll(this);
++            return cloned;
++
++        } catch (CloneNotSupportedException ex) {
++            return null;  // should never happen
++        }
++    }
++
++    /**
++     * Compares this map with another.
++     *
++     * @param obj the object to compare to
++     * @return true if equal
++     */
++    public boolean equals(Object obj) {
++        if (obj == this) {
++            return true;
++        }
++        if (obj instanceof Map == false) {
++            return false;
++        }
++        Map map = (Map) obj;
++        if (map.size() != size()) {
++            return false;
++        }
++        MapIterator it = mapIterator();
++        try {
++            while (it.hasNext()) {
++                Object key = it.next();
++                Object value = it.getValue();
++                if (value == null) {
++                    if (map.get(key) != null || map.containsKey(key) == false) {
++                        return false;
++                    }
++                } else {
++                    if (value.equals(map.get(key)) == false) {
++                        return false;
++                    }
++                }
++            }
++        } catch (ClassCastException ignored) {
++            return false;
++        } catch (NullPointerException ignored) {
++            return false;
++        }
++        return true;
++    }
++
++    /**
++     * Gets the standard Map hashCode.
++     *
++     * @return the hash code defined in the Map interface
++     */
++    public int hashCode() {
++        int total = 0;
++        Iterator it = createEntrySetIterator();
++        while (it.hasNext()) {
++            total += it.next().hashCode();
++        }
++        return total;
++    }
++
++    /**
++     * Gets the map as a String.
++     *
++     * @return a string version of the map
++     */
++    public String toString() {
++        if (size() == 0) {
++            return "{}";
++        }
++        StringBuffer buf = new StringBuffer(32 * size());
++        buf.append('{');
++
++        MapIterator it = mapIterator();
++        boolean hasNext = it.hasNext();
++        while (hasNext) {
++            Object key = it.next();
++            Object value = it.getValue();
++            buf.append(key == this ? "(this Map)" : key).append('=').append(value == this ? "(this Map)" : value);
++
++            hasNext = it.hasNext();
++            if (hasNext) {
++                buf.append(',').append(' ');
++            }
++        }
++
++        buf.append('}');
++        return buf.toString();
++    }
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/AbstractInputCheckedMapDecorator.java
+@@ -0,0 +1,199 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.iterators.AbstractIteratorDecorator;
++import org.apache.commons.collections15.keyvalue.AbstractMapEntryDecorator;
++import org.apache.commons.collections15.set.AbstractSetDecorator;
++
++import java.lang.reflect.Array;
++import java.util.Iterator;
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * An abstract base class that simplifies the task of creating map decorators.
++ * <p/>
++ * The Map API is very difficult to decorate correctly, and involves implementing
++ * lots of different classes. This class exists to provide a simpler API.
++ * <p/>
++ * Special hook methods are provided that are called when objects are added to
++ * the map. By overriding these methods, the input can be validated or manipulated.
++ * In addition to the main map methods, the entrySet is also affected, which is
++ * the hardest part of writing map implementations.
++ * <p/>
++ * This class is package-scoped, and may be withdrawn or replaced in future
++ * versions of Commons Collections.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.1
++ */
++abstract class AbstractInputCheckedMapDecorator <K,V> extends AbstractMapDecorator<K, V> {
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     */
++    protected AbstractInputCheckedMapDecorator() {
++        super();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    protected AbstractInputCheckedMapDecorator(Map<K, V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Hook method called when a value is being set using <code>setValue</code>.
++     * <p/>
++     * An implementation may validate the value and throw an exception
++     * or it may transform the value into another object.
++     * <p/>
++     * This implementation returns the input value.
++     *
++     * @param value the value to check
++     * @throws UnsupportedOperationException if the map may not be changed by setValue
++     * @throws IllegalArgumentException      if the specified value is invalid
++     * @throws ClassCastException            if the class of the specified value is invalid
++     * @throws NullPointerException          if the specified value is null and nulls are invalid
++     */
++    protected abstract V checkSetValue(V value);
++
++    /**
++     * Hook method called to determine if <code>checkSetValue</code> has any effect.
++     * <p/>
++     * An implementation should return false if the <code>checkSetValue</code> method
++     * has no effect as this optimises the implementation.
++     * <p/>
++     * This implementation returns <code>true</code>.
++     */
++    protected boolean isSetValueChecking() {
++        return true;
++    }
++
++    //-----------------------------------------------------------------------
++    public Set<Map.Entry<K, V>> entrySet() {
++        if (isSetValueChecking()) {
++            return new EntrySet<K, V>(map.entrySet(), this);
++        } else {
++            return map.entrySet();
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Implementation of an entry set that checks additions via setValue.
++     */
++    static class EntrySet <K,V> extends AbstractSetDecorator<Map.Entry<K, V>> {
++
++        /**
++         * The parent map
++         */
++        private final AbstractInputCheckedMapDecorator<K, V> parent;
++
++        protected EntrySet(Set<Map.Entry<K, V>> set, AbstractInputCheckedMapDecorator<K, V> parent) {
++            super(set);
++            this.parent = parent;
++        }
++
++        public Iterator<Map.Entry<K, V>> iterator() {
++            return new EntrySetIterator<K, V>(collection.iterator(), parent);
++        }
++
++        public Object[] toArray() {
++            Object[] array = collection.toArray();
++            for (int i = 0; i < array.length; i++) {
++                array[i] = new MapEntry((Map.Entry) array[i], parent);
++            }
++            return array;
++        }
++
++        public <T> T[] toArray(T array[]) {
++            Object[] result = array;
++            if (array.length > 0) {
++                // we must create a new array to handle multi-threaded situations
++                // where another thread could access data before we decorate it
++                result = (T[]) Array.newInstance(array.getClass().getComponentType(), 0);
++            }
++            result = collection.toArray(result);
++            for (int i = 0; i < result.length; i++) {
++                result[i] = new MapEntry((Map.Entry) result[i], parent);
++            }
++
++            // check to see if result should be returned straight
++            if (result.length > array.length) {
++                return (T[]) result;
++            }
++
++            // copy back into input array to fulfil the method contract
++            System.arraycopy(result, 0, array, 0, result.length);
++            if (array.length > result.length) {
++                array[result.length] = null;
++            }
++            return (T[]) array;
++        }
++    }
++
++    /**
++     * Implementation of an entry set iterator that checks additions via setValue.
++     */
++    static class EntrySetIterator <K,V> extends AbstractIteratorDecorator<Map.Entry<K, V>> {
++
++        /**
++         * The parent map
++         */
++        private final AbstractInputCheckedMapDecorator<K, V> parent;
++
++        protected EntrySetIterator(Iterator<Map.Entry<K, V>> iterator, AbstractInputCheckedMapDecorator<K, V> parent) {
++            super(iterator);
++            this.parent = parent;
++        }
++
++        public Map.Entry<K, V> next() {
++            Map.Entry<K, V> entry = iterator.next();
++            return new MapEntry<K, V>(entry, parent);
++        }
++    }
++
++    /**
++     * Implementation of a map entry that checks additions via setValue.
++     */
++    static class MapEntry <K,V> extends AbstractMapEntryDecorator<K, V> {
++
++        /**
++         * The parent map
++         */
++        private final AbstractInputCheckedMapDecorator<K, V> parent;
++
++        protected MapEntry(Map.Entry<K, V> entry, AbstractInputCheckedMapDecorator<K, V> parent) {
++            super(entry);
++            this.parent = parent;
++        }
++
++        public V setValue(V value) {
++            value = parent.checkSetValue(value);
++            return entry.setValue(value);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/AbstractLinkedMap.java
+@@ -0,0 +1,617 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.*;
++import org.apache.commons.collections15.iterators.EmptyOrderedIterator;
++import org.apache.commons.collections15.iterators.EmptyOrderedMapIterator;
++
++import java.util.ConcurrentModificationException;
++import java.util.Iterator;
++import java.util.Map;
++import java.util.NoSuchElementException;
++
++/**
++ * An abstract implementation of a hash-based map that links entries to create an
++ * ordered map and which provides numerous points for subclasses to override.
++ * <p/>
++ * This class implements all the features necessary for a subclass linked
++ * hash-based map. Key-value entries are stored in instances of the
++ * <code>LinkEntry</code> class which can be overridden and replaced.
++ * The iterators can similarly be replaced, without the need to replace the KeySet,
++ * EntrySet and Values view classes.
++ * <p/>
++ * Overridable methods are provided to change the default hashing behaviour, and
++ * to change how entries are added to and removed from the map. Hopefully, all you
++ * need for unusual subclasses is here.
++ * <p/>
++ * This implementation maintains order by original insertion, but subclasses
++ * may work differently. The <code>OrderedMap</code> interface is implemented
++ * to provide access to bidirectional iteration and extra convenience methods.
++ * <p/>
++ * The <code>orderedMapIterator()</code> method provides direct access to a
++ * bidirectional iterator. The iterators from the other views can also be cast
++ * to <code>OrderedIterator</code> if required.
++ * <p/>
++ * All the available iterators can be reset back to the start by casting to
++ * <code>ResettableIterator</code> and calling <code>reset()</code>.
++ * <p/>
++ * The implementation is also designed to be subclassed, with lots of useful
++ * methods exposed.
++ *
++ * @author java util LinkedHashMap
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class AbstractLinkedMap <K,V> extends AbstractHashedMap<K, V> implements OrderedMap<K, V> {
++
++    /**
++     * Header in the linked list
++     */
++    protected transient LinkEntry<K, V> header;
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     */
++    protected AbstractLinkedMap() {
++        super();
++    }
++
++    /**
++     * Constructor which performs no validation on the passed in parameters.
++     *
++     * @param initialCapacity the initial capacity, must be a power of two
++     * @param loadFactor      the load factor, must be > 0.0f and generally < 1.0f
++     * @param threshold       the threshold, must be sensible
++     */
++    protected AbstractLinkedMap(int initialCapacity, float loadFactor, int threshold) {
++        super(initialCapacity, loadFactor, threshold);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity.
++     *
++     * @param initialCapacity the initial capacity
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     */
++    protected AbstractLinkedMap(int initialCapacity) {
++        super(initialCapacity);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity and
++     * load factor.
++     *
++     * @param initialCapacity the initial capacity
++     * @param loadFactor      the load factor
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     * @throws IllegalArgumentException if the load factor is less than zero
++     */
++    protected AbstractLinkedMap(int initialCapacity, float loadFactor) {
++        super(initialCapacity, loadFactor);
++    }
++
++    /**
++     * Constructor copying elements from another map.
++     *
++     * @param map the map to copy
++     * @throws NullPointerException if the map is null
++     */
++    protected AbstractLinkedMap(Map<? extends K, ? extends V> map) {
++        super(map);
++    }
++
++    /**
++     * Initialise this subclass during construction.
++     */
++    protected void init() {
++        header = new LinkEntry<K, V>(null, -1, null, null);
++        header.before = header.after = header;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Checks whether the map contains the specified value.
++     *
++     * @param value the value to search for
++     * @return true if the map contains the value
++     */
++    public boolean containsValue(Object value) {
++        // override uses faster iterator
++        if (value == null) {
++            for (LinkEntry entry = header.after; entry != header; entry = entry.after) {
++                if (entry.getValue() == null) {
++                    return true;
++                }
++            }
++        } else {
++            for (LinkEntry entry = header.after; entry != header; entry = entry.after) {
++                if (isEqualValue(value, entry.getValue())) {
++                    return true;
++                }
++            }
++        }
++        return false;
++    }
++
++    /**
++     * Clears the map, resetting the size to zero and nullifying references
++     * to avoid garbage collection issues.
++     */
++    public void clear() {
++        // override to reset the linked list
++        super.clear();
++        header.before = header.after = header;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the first key in the map, which is the most recently inserted.
++     *
++     * @return the most recently inserted key
++     */
++    public K firstKey() {
++        if (size == 0) {
++            throw new NoSuchElementException("Map is empty");
++        }
++        return header.after.getKey();
++    }
++
++    /**
++     * Gets the last key in the map, which is the first inserted.
++     *
++     * @return the eldest key
++     */
++    public K lastKey() {
++        if (size == 0) {
++            throw new NoSuchElementException("Map is empty");
++        }
++        return header.before.getKey();
++    }
++
++    /**
++     * Gets the next key in sequence.
++     *
++     * @param key the key to get after
++     * @return the next key
++     */
++    public K nextKey(K key) {
++        LinkEntry<K, V> entry = (LinkEntry<K, V>) getEntry(key);
++        return (entry == null || entry.after == header ? null : entry.after.getKey());
++    }
++
++    /**
++     * Gets the previous key in sequence.
++     *
++     * @param key the key to get before
++     * @return the previous key
++     */
++    public K previousKey(K key) {
++        LinkEntry<K, V> entry = (LinkEntry<K, V>) getEntry(key);
++        return (entry == null || entry.before == header ? null : entry.before.getKey());
++    }
++
++    //-----------------------------------------------------------------------    
++    /**
++     * Gets the key at the specified index.
++     *
++     * @param index the index to retrieve
++     * @return the key at the specified index
++     * @throws IndexOutOfBoundsException if the index is invalid
++     */
++    protected LinkEntry<K, V> getEntry(int index) {
++        if (index < 0) {
++            throw new IndexOutOfBoundsException("Index " + index + " is less than zero");
++        }
++        if (index >= size) {
++            throw new IndexOutOfBoundsException("Index " + index + " is invalid for size " + size);
++        }
++        LinkEntry<K, V> entry;
++        if (index < (size / 2)) {
++            // Search forwards
++            entry = header.after;
++            for (int currentIndex = 0; currentIndex < index; currentIndex++) {
++                entry = entry.after;
++            }
++        } else {
++            // Search backwards
++            entry = header;
++            for (int currentIndex = size; currentIndex > index; currentIndex--) {
++                entry = entry.before;
++            }
++        }
++        return entry;
++    }
++
++    /**
++     * Adds an entry into this map, maintaining insertion order.
++     * <p/>
++     * This implementation adds the entry to the data storage table and
++     * to the end of the linked list.
++     *
++     * @param entry     the entry to add
++     * @param hashIndex the index into the data array to store at
++     */
++    protected void addEntry(HashEntry<K, V> entry, int hashIndex) {
++        LinkEntry<K, V> link = (LinkEntry<K, V>) entry;
++        link.after = header;
++        link.before = header.before;
++        header.before.after = link;
++        header.before = link;
++        data[hashIndex] = entry;
++    }
++
++    /**
++     * Creates an entry to store the data.
++     * <p/>
++     * This implementation creates a new LinkEntry instance.
++     *
++     * @param next     the next entry in sequence
++     * @param hashCode the hash code to use
++     * @param key      the key to store
++     * @param value    the value to store
++     * @return the newly created entry
++     */
++    protected HashEntry<K, V> createEntry(HashEntry<K, V> next, int hashCode, K key, V value) {
++        return new LinkEntry<K, V>(next, hashCode, key, value);
++    }
++
++    /**
++     * Removes an entry from the map and the linked list.
++     * <p/>
++     * This implementation removes the entry from the linked list chain, then
++     * calls the superclass implementation.
++     *
++     * @param entry     the entry to remove
++     * @param hashIndex the index into the data structure
++     * @param previous  the previous entry in the chain
++     */
++    protected void removeEntry(HashEntry<K, V> entry, int hashIndex, HashEntry<K, V> previous) {
++        LinkEntry<K, V> link = (LinkEntry<K, V>) entry;
++        link.before.after = link.after;
++        link.after.before = link.before;
++        link.after = null;
++        link.before = null;
++        super.removeEntry(entry, hashIndex, previous);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the <code>before</code> field from a <code>LinkEntry</code>.
++     * Used in subclasses that have no visibility of the field.
++     *
++     * @param entry the entry to query, must not be null
++     * @return the <code>before</code> field of the entry
++     * @throws NullPointerException if the entry is null
++     * @since Commons Collections 3.1
++     */
++    protected LinkEntry<K, V> entryBefore(LinkEntry<K, V> entry) {
++        return entry.before;
++    }
++
++    /**
++     * Gets the <code>after</code> field from a <code>LinkEntry</code>.
++     * Used in subclasses that have no visibility of the field.
++     *
++     * @param entry the entry to query, must not be null
++     * @return the <code>after</code> field of the entry
++     * @throws NullPointerException if the entry is null
++     * @since Commons Collections 3.1
++     */
++    protected LinkEntry<K, V> entryAfter(LinkEntry<K, V> entry) {
++        return entry.after;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator over the map.
++     * Changes made to the iterator affect this map.
++     * <p/>
++     * A MapIterator returns the keys in the map. It also provides convenient
++     * methods to get the key and value, and set the value.
++     * It avoids the need to create an entrySet/keySet/values object.
++     *
++     * @return the map iterator
++     */
++    public MapIterator<K, V> mapIterator() {
++        if (size == 0) {
++            return EmptyOrderedMapIterator.INSTANCE;
++        }
++        return new LinkMapIterator<K, V>(this);
++    }
++
++    /**
++     * Gets a bidirectional iterator over the map.
++     * Changes made to the iterator affect this map.
++     * <p/>
++     * A MapIterator returns the keys in the map. It also provides convenient
++     * methods to get the key and value, and set the value.
++     * It avoids the need to create an entrySet/keySet/values object.
++     *
++     * @return the map iterator
++     */
++    public OrderedMapIterator<K, V> orderedMapIterator() {
++        if (size == 0) {
++            return EmptyOrderedMapIterator.INSTANCE;
++        }
++        return new LinkMapIterator<K, V>(this);
++    }
++
++    /**
++     * MapIterator implementation.
++     */
++    protected static class LinkMapIterator <K,V> extends LinkIterator<K, V> implements OrderedMapIterator<K, V>, OrderedIterator<K>, ResettableIterator<K> {
++
++        protected LinkMapIterator(AbstractLinkedMap<K, V> parent) {
++            super(parent);
++        }
++
++        public K next() {
++            return super.nextEntry().getKey();
++        }
++
++        public K previous() {
++            return super.previousEntry().getKey();
++        }
++
++        public K getKey() {
++            HashEntry<K, V> current = currentEntry();
++            if (current == null) {
++                throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
++            }
++            return current.getKey();
++        }
++
++        public V getValue() {
++            HashEntry<K, V> current = currentEntry();
++            if (current == null) {
++                throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
++            }
++            return current.getValue();
++        }
++
++        public V setValue(V value) {
++            HashEntry<K, V> current = currentEntry();
++            if (current == null) {
++                throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
++            }
++            return current.setValue(value);
++        }
++    }
++    
++    //-----------------------------------------------------------------------    
++    /**
++     * Creates an entry set iterator.
++     * Subclasses can override this to return iterators with different properties.
++     *
++     * @return the entrySet iterator
++     */
++    protected Iterator<Map.Entry<K, V>> createEntrySetIterator() {
++        if (size() == 0) {
++            return EmptyOrderedIterator.INSTANCE;
++        }
++        return new EntrySetIterator<K, V>(this);
++    }
++
++    /**
++     * EntrySet iterator.
++     */
++    protected static class EntrySetIterator <K,V> extends LinkIterator<K, V> implements OrderedIterator<Map.Entry<K, V>>, ResettableIterator<Map.Entry<K, V>> {
++
++        protected EntrySetIterator(AbstractLinkedMap<K, V> parent) {
++            super(parent);
++        }
++
++        public Map.Entry<K, V> next() {
++            return super.nextEntry();
++        }
++
++        public Map.Entry<K, V> previous() {
++            return super.previousEntry();
++        }
++    }
++
++    //-----------------------------------------------------------------------    
++    /**
++     * Creates a key set iterator.
++     * Subclasses can override this to return iterators with different properties.
++     *
++     * @return the keySet iterator
++     */
++    protected Iterator createKeySetIterator() {
++        if (size() == 0) {
++            return EmptyOrderedIterator.INSTANCE;
++        }
++        return new KeySetIterator(this);
++    }
++
++    /**
++     * KeySet iterator.
++     */
++    protected static class KeySetIterator <K,V> extends LinkIterator<K, V> implements OrderedIterator<K>, ResettableIterator<K> {
++
++        protected KeySetIterator(AbstractLinkedMap<K, V> parent) {
++            super(parent);
++        }
++
++        public K next() {
++            return super.nextEntry().getKey();
++        }
++
++        public K previous() {
++            return super.previousEntry().getKey();
++        }
++    }
++    
++    //-----------------------------------------------------------------------    
++    /**
++     * Creates a values iterator.
++     * Subclasses can override this to return iterators with different properties.
++     *
++     * @return the values iterator
++     */
++    protected Iterator<V> createValuesIterator() {
++        if (size() == 0) {
++            return EmptyOrderedIterator.INSTANCE;
++        }
++        return new ValuesIterator<K, V>(this);
++    }
++
++    /**
++     * Values iterator.
++     */
++    protected static class ValuesIterator <K,V> extends LinkIterator<K, V> implements OrderedIterator<V>, ResettableIterator<V> {
++
++        protected ValuesIterator(AbstractLinkedMap<K, V> parent) {
++            super(parent);
++        }
++
++        public V next() {
++            return super.nextEntry().getValue();
++        }
++
++        public V previous() {
++            return super.previousEntry().getValue();
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * LinkEntry that stores the data.
++     * <p/>
++     * If you subclass <code>AbstractLinkedMap</code> but not <code>LinkEntry</code>
++     * then you will not be able to access the protected fields.
++     * The <code>entryXxx()</code> methods on <code>AbstractLinkedMap</code> exist
++     * to provide the necessary access.
++     */
++    protected static class LinkEntry <K,V> extends HashEntry<K, V> {
++        /**
++         * The entry before this one in the order
++         */
++        protected LinkEntry<K, V> before;
++        /**
++         * The entry after this one in the order
++         */
++        protected LinkEntry<K, V> after;
++
++        /**
++         * Constructs a new entry.
++         *
++         * @param next     the next entry in the hash bucket sequence
++         * @param hashCode the hash code
++         * @param key      the key
++         * @param value    the value
++         */
++        protected LinkEntry(HashEntry<K, V> next, int hashCode, K key, V value) {
++            super(next, hashCode, key, value);
++        }
++    }
++
++    /**
++     * Base Iterator that iterates in link order.
++     */
++    protected static abstract class LinkIterator <K,V> {
++
++        /**
++         * The parent map
++         */
++        protected final AbstractLinkedMap<K, V> parent;
++        /**
++         * The current (last returned) entry
++         */
++        protected LinkEntry<K, V> last;
++        /**
++         * The next entry
++         */
++        protected LinkEntry<K, V> next;
++        /**
++         * The modification count expected
++         */
++        protected int expectedModCount;
++
++        protected LinkIterator(AbstractLinkedMap<K, V> parent) {
++            super();
++            this.parent = parent;
++            this.next = parent.header.after;
++            this.expectedModCount = parent.modCount;
++        }
++
++        public boolean hasNext() {
++            return (next != parent.header);
++        }
++
++        public boolean hasPrevious() {
++            return (next.before != parent.header);
++        }
++
++        protected LinkEntry<K, V> nextEntry() {
++            if (parent.modCount != expectedModCount) {
++                throw new ConcurrentModificationException();
++            }
++            if (next == parent.header) {
++                throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
++            }
++            last = next;
++            next = next.after;
++            return last;
++        }
++
++        protected LinkEntry<K, V> previousEntry() {
++            if (parent.modCount != expectedModCount) {
++                throw new ConcurrentModificationException();
++            }
++            LinkEntry<K, V> previous = next.before;
++            if (previous == parent.header) {
++                throw new NoSuchElementException(AbstractHashedMap.NO_PREVIOUS_ENTRY);
++            }
++            next = previous;
++            last = previous;
++            return last;
++        }
++
++        protected LinkEntry<K, V> currentEntry() {
++            return last;
++        }
++
++        public void remove() {
++            if (last == null) {
++                throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
++            }
++            if (parent.modCount != expectedModCount) {
++                throw new ConcurrentModificationException();
++            }
++            parent.remove(last.getKey());
++            last = null;
++            expectedModCount = parent.modCount;
++        }
++
++        public void reset() {
++            last = null;
++            next = parent.header.after;
++        }
++
++        public String toString() {
++            if (last != null) {
++                return "Iterator[" + last.getKey() + "=" + last.getValue() + "]";
++            } else {
++                return "Iterator[]";
++            }
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/AbstractMapDecorator.java
+@@ -0,0 +1,143 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import java.util.Collection;
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * Provides a base decorator that enables additional functionality to be added
++ * to a Map via decoration.
++ * <p/>
++ * Methods are forwarded directly to the decorated map.
++ * <p/>
++ * This implementation does not perform any special processing with
++ * {@link #entrySet()}, {@link #keySet()} or {@link #values()}. Instead
++ * it simply returns the set/collection from the wrapped map. This may be
++ * undesirable, for example if you are trying to write a validating
++ * implementation it would provide a loophole around the validation.
++ * But, you might want that loophole, so this class is kept simple.
++ *
++ * @author Daniel Rall
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractMapDecorator <K,V> implements Map<K, V> {
++
++    /**
++     * The map to decorate
++     */
++    protected transient Map<K, V> map;
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     *
++     * @since Commons Collections 3.1
++     */
++    protected AbstractMapDecorator() {
++        super();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    public AbstractMapDecorator(Map<K, V> map) {
++        if (map == null) {
++            throw new IllegalArgumentException("Map must not be null");
++        }
++        this.map = map;
++    }
++
++    /**
++     * Gets the map being decorated.
++     *
++     * @return the decorated map
++     */
++    protected Map<K, V> getMap() {
++        return map;
++    }
++
++    //-----------------------------------------------------------------------
++    public void clear() {
++        map.clear();
++    }
++
++    public boolean containsKey(Object key) {
++        return map.containsKey(key);
++    }
++
++    public boolean containsValue(Object value) {
++        return map.containsValue(value);
++    }
++
++    public Set<Map.Entry<K, V>> entrySet() {
++        return map.entrySet();
++    }
++
++    public V get(Object key) {
++        return map.get(key);
++    }
++
++    public boolean isEmpty() {
++        return map.isEmpty();
++    }
++
++    public Set<K> keySet() {
++        return map.keySet();
++    }
++
++    public V put(K key, V value) {
++        return map.put(key, value);
++    }
++
++    public void putAll(Map<? extends K, ? extends V> mapToCopy) {
++        map.putAll(mapToCopy);
++    }
++
++    public V remove(Object key) {
++        return map.remove(key);
++    }
++
++    public int size() {
++        return map.size();
++    }
++
++    public Collection<V> values() {
++        return map.values();
++    }
++
++    public boolean equals(Object object) {
++        if (object == this) {
++            return true;
++        }
++        return map.equals(object);
++    }
++
++    public int hashCode() {
++        return map.hashCode();
++    }
++
++    public String toString() {
++        return map.toString();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/AbstractOrderedMapDecorator.java
+@@ -0,0 +1,94 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.OrderedMap;
++import org.apache.commons.collections15.OrderedMapIterator;
++
++/**
++ * Provides a base decorator that enables additional functionality to be added
++ * to an OrderedMap via decoration.
++ * <p/>
++ * Methods are forwarded directly to the decorated map.
++ * <p/>
++ * This implementation does not perform any special processing with the map views.
++ * Instead it simply returns the set/collection from the wrapped map. This may be
++ * undesirable, for example if you are trying to write a validating implementation
++ * it would provide a loophole around the validation.
++ * But, you might want that loophole, so this class is kept simple.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractOrderedMapDecorator <K,V> extends AbstractMapDecorator<K, V> implements OrderedMap<K, V> {
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     *
++     * @since Commons Collections 3.1
++     */
++    protected AbstractOrderedMapDecorator() {
++        super();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    public AbstractOrderedMapDecorator(OrderedMap<K, V> map) {
++        super(map);
++    }
++
++    /**
++     * Gets the map being decorated.
++     *
++     * @return the decorated map
++     */
++    protected OrderedMap<K, V> getOrderedMap() {
++        return (OrderedMap<K, V>) map;
++    }
++
++    //-----------------------------------------------------------------------
++    public K firstKey() {
++        return getOrderedMap().firstKey();
++    }
++
++    public K lastKey() {
++        return getOrderedMap().lastKey();
++    }
++
++    public K nextKey(K key) {
++        return getOrderedMap().nextKey(key);
++    }
++
++    public K previousKey(K key) {
++        return getOrderedMap().previousKey(key);
++    }
++
++    public MapIterator<K, V> mapIterator() {
++        return getOrderedMap().mapIterator();
++    }
++
++    public OrderedMapIterator<K, V> orderedMapIterator() {
++        return getOrderedMap().orderedMapIterator();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/AbstractReferenceMap.java
+@@ -0,0 +1,1028 @@
++// Converted, with some major refactors required. Not as memory-efficient as before, could use additional refactoring.
++// Perhaps use four different types of HashEntry classes for max efficiency:
++//   normal HashEntry for HARD,HARD
++//   HardRefEntry for HARD,(SOFT|WEAK)
++//   RefHardEntry for (SOFT|WEAK),HARD
++//   RefRefEntry for (SOFT|WEAK),(SOFT|WEAK)
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.keyvalue.DefaultMapEntry;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.lang.ref.Reference;
++import java.lang.ref.ReferenceQueue;
++import java.lang.ref.SoftReference;
++import java.lang.ref.WeakReference;
++import java.util.*;
++
++/**
++ * An abstract implementation of a hash-based map that allows the entries to
++ * be removed by the garbage collector.
++ * <p/>
++ * This class implements all the features necessary for a subclass reference
++ * hash-based map. Key-value entries are stored in instances of the
++ * <code>ReferenceEntry</code> class which can be overridden and replaced.
++ * The iterators can similarly be replaced, without the need to replace the KeySet,
++ * EntrySet and Values view classes.
++ * <p/>
++ * Overridable methods are provided to change the default hashing behaviour, and
++ * to change how entries are added to and removed from the map. Hopefully, all you
++ * need for unusual subclasses is here.
++ * <p/>
++ * When you construct an <code>AbstractReferenceMap</code>, you can specify what
++ * kind of references are used to store the map's keys and values.
++ * If non-hard references are used, then the garbage collector can remove
++ * mappings if a key or value becomes unreachable, or if the JVM's memory is
++ * running low. For information on how the different reference types behave,
++ * see {@link Reference}.
++ * <p/>
++ * Different types of references can be specified for keys and values.
++ * The keys can be configured to be weak but the values hard,
++ * in which case this class will behave like a
++ * <a href="http://java.sun.com/j2se/1.4/docs/api/java/util/WeakHashMap.html">
++ * <code>WeakHashMap</code></a>. However, you can also specify hard keys and
++ * weak values, or any other combination. The default constructor uses
++ * hard keys and soft values, providing a memory-sensitive cache.
++ * <p/>
++ * This {@link Map} implementation does <i>not</i> allow null elements.
++ * Attempting to add a null key or value to the map will raise a
++ * <code>NullPointerException</code>.
++ * <p/>
++ * All the available iterators can be reset back to the start by casting to
++ * <code>ResettableIterator</code> and calling <code>reset()</code>.
++ * <p/>
++ * This implementation is not synchronized.
++ * You can use {@link java.util.Collections#synchronizedMap} to
++ * provide synchronized access to a <code>ReferenceMap</code>.
++ *
++ * @author Paul Jack
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @see java.lang.ref.Reference
++ * @since Commons Collections 3.1 (extracted from ReferenceMap in 3.0)
++ */
++public abstract class AbstractReferenceMap <K,V> extends AbstractHashedMap<K, V> {
++
++    /**
++     * Constant indicating that hard references should be used
++     */
++    public static final int HARD = 0;
++
++    /**
++     * Constant indicating that soft references should be used
++     */
++    public static final int SOFT = 1;
++
++    /**
++     * Constant indicating that weak references should be used
++     */
++    public static final int WEAK = 2;
++
++    /**
++     * The reference type for keys.  Must be HARD, SOFT, WEAK.
++     *
++     * @serial
++     */
++    protected int keyType;
++
++    /**
++     * The reference type for values.  Must be HARD, SOFT, WEAK.
++     *
++     * @serial
++     */
++    protected int valueType;
++
++    /**
++     * Should the value be automatically purged when the associated key has been collected?
++     */
++    protected boolean purgeValues;
++
++    /**
++     * ReferenceQueue used to eliminate stale mappings.
++     * See purge.
++     */
++    private transient ReferenceQueue queue;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor used during deserialization.
++     */
++    protected AbstractReferenceMap() {
++        super();
++    }
++
++    /**
++     * Constructs a new empty map with the specified reference types,
++     * load factor and initial capacity.
++     *
++     * @param keyType     the type of reference to use for keys;
++     *                    must be {@link #SOFT} or {@link #WEAK}
++     * @param valueType   the type of reference to use for values;
++     *                    must be {@link #SOFT} or {@link #WEAK}
++     * @param capacity    the initial capacity for the map
++     * @param loadFactor  the load factor for the map
++     * @param purgeValues should the value be automatically purged when the
++     *                    key is garbage collected
++     */
++    protected AbstractReferenceMap(int keyType, int valueType, int capacity, float loadFactor, boolean purgeValues) {
++        super(capacity, loadFactor);
++        verify("keyType", keyType);
++        verify("valueType", valueType);
++        this.keyType = keyType;
++        this.valueType = valueType;
++        this.purgeValues = purgeValues;
++    }
++
++    /**
++     * Initialise this subclass during construction, cloning or deserialization.
++     */
++    protected void init() {
++        queue = new ReferenceQueue();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Checks the type int is a valid value.
++     *
++     * @param name the name for error messages
++     * @param type the type value to check
++     * @throws IllegalArgumentException if the value if invalid
++     */
++    private static void verify(String name, int type) {
++        if ((type < HARD) || (type > WEAK)) {
++            throw new IllegalArgumentException(name + " must be HARD, SOFT, WEAK.");
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the size of the map.
++     *
++     * @return the size
++     */
++    public int size() {
++        purgeBeforeRead();
++        return super.size();
++    }
++
++    /**
++     * Checks whether the map is currently empty.
++     *
++     * @return true if the map is currently size zero
++     */
++    public boolean isEmpty() {
++        purgeBeforeRead();
++        return super.isEmpty();
++    }
++
++    /**
++     * Checks whether the map contains the specified key.
++     *
++     * @param key the key to search for
++     * @return true if the map contains the key
++     */
++    public boolean containsKey(Object key) {
++        purgeBeforeRead();
++        Entry entry = getEntry(key);
++        if (entry == null) {
++            return false;
++        }
++        return (entry.getValue() != null);
++    }
++
++    /**
++     * Checks whether the map contains the specified value.
++     *
++     * @param value the value to search for
++     * @return true if the map contains the value
++     */
++    public boolean containsValue(Object value) {
++        purgeBeforeRead();
++        if (value == null) {
++            return false;
++        }
++        return super.containsValue(value);
++    }
++
++    /**
++     * Gets the value mapped to the key specified.
++     *
++     * @param key the key
++     * @return the mapped value, null if no match
++     */
++    public V get(Object key) {
++        purgeBeforeRead();
++        Entry<K, V> entry = getEntry(key);
++        if (entry == null) {
++            return null;
++        }
++        return entry.getValue();
++    }
++
++
++    /**
++     * Puts a key-value mapping into this map.
++     * Neither the key nor the value may be null.
++     *
++     * @param key   the key to add, must not be null
++     * @param value the value to add, must not be null
++     * @return the value previously mapped to this key, null if none
++     * @throws NullPointerException if either the key or value is null
++     */
++    public V put(K key, V value) {
++        if (key == null) {
++            throw new NullPointerException("null keys not allowed");
++        }
++        if (value == null) {
++            throw new NullPointerException("null values not allowed");
++        }
++
++        purgeBeforeWrite();
++        return super.put(key, value);
++    }
++
++    /**
++     * Removes the specified mapping from this map.
++     *
++     * @param key the mapping to remove
++     * @return the value mapped to the removed key, null if key not in map
++     */
++    public V remove(Object key) {
++        if (key == null) {
++            return null;
++        }
++        purgeBeforeWrite();
++        return super.remove(key);
++    }
++
++    /**
++     * Clears this map.
++     */
++    public void clear() {
++        super.clear();
++        while (queue.poll() != null) {
++        } // drain the queue
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets a MapIterator over the reference map.
++     * The iterator only returns valid key/value pairs.
++     *
++     * @return a map iterator
++     */
++    public MapIterator<K, V> mapIterator() {
++        return new ReferenceMapIterator<K, V>(this);
++    }
++
++    /**
++     * Returns a set view of this map's entries.
++     * An iterator returned entry is valid until <code>next()</code> is called again.
++     * The <code>setValue()</code> method on the <code>toArray</code> entries has no effect.
++     *
++     * @return a set view of this map's entries
++     */
++    public Set<Map.Entry<K, V>> entrySet() {
++        if (entrySet == null) {
++            entrySet = new ReferenceEntrySet<K, V>(this);
++        }
++        return entrySet;
++    }
++
++    /**
++     * Returns a set view of this map's keys.
++     *
++     * @return a set view of this map's keys
++     */
++    public Set<K> keySet() {
++        if (keySet == null) {
++            keySet = new ReferenceKeySet<K, V>(this);
++        }
++        return keySet;
++    }
++
++    /**
++     * Returns a collection view of this map's values.
++     *
++     * @return a set view of this map's values
++     */
++    public Collection<V> values() {
++        if (values == null) {
++            values = new ReferenceValues<K, V>(this);
++        }
++        return values;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Purges stale mappings from this map before read operations.
++     * <p/>
++     * This implementation calls {@link #purge()} to maintain a consistent state.
++     */
++    protected void purgeBeforeRead() {
++        purge();
++    }
++
++    /**
++     * Purges stale mappings from this map before write operations.
++     * <p/>
++     * This implementation calls {@link #purge()} to maintain a consistent state.
++     */
++    protected void purgeBeforeWrite() {
++        purge();
++    }
++
++    /**
++     * Purges stale mappings from this map.
++     * <p/>
++     * Note that this method is not synchronized!  Special
++     * care must be taken if, for instance, you want stale
++     * mappings to be removed on a periodic basis by some
++     * background thread.
++     */
++    protected void purge() {
++        Reference ref = queue.poll();
++        while (ref != null) {
++            purge(ref);
++            ref = queue.poll();
++        }
++    }
++
++    /**
++     * Purges the specified reference.
++     *
++     * @param ref the reference to purge
++     */
++    protected void purge(Reference ref) {
++        // The hashCode of the reference is the hashCode of the
++        // mapping key, even if the reference refers to the 
++        // mapping value...
++        int hash = ref.hashCode();
++        int index = hashIndex(hash, data.length);
++        HashEntry<K, V> previous = null;
++        HashEntry<K, V> entry = data[index];
++        while (entry != null) {
++            if (((ReferenceEntry<K, V>) entry).purge(ref)) {
++                if (previous == null) {
++                    data[index] = entry.next;
++                } else {
++                    previous.next = entry.next;
++                }
++                this.size--;
++                return;
++            }
++            previous = entry;
++            entry = entry.next;
++        }
++
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the entry mapped to the key specified.
++     *
++     * @param key the key
++     * @return the entry, null if no match
++     */
++    protected HashEntry<K, V> getEntry(Object key) {
++        if (key == null) {
++            return null;
++        } else {
++            return super.getEntry(key);
++        }
++    }
++
++    /**
++     * Gets the hash code for a MapEntry.
++     * Subclasses can override this, for example to use the identityHashCode.
++     *
++     * @param key   the key to get a hash code for, may be null
++     * @param value the value to get a hash code for, may be null
++     * @return the hash code, as per the MapEntry specification
++     */
++    protected int hashEntry(Object key, Object value) {
++        return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
++    }
++
++    /**
++     * Compares two keys, in internal converted form, to see if they are equal.
++     * <p/>
++     * This implementation converts the key from the entry to a real reference
++     * before comparison.
++     *
++     * @param key1 the first key to compare passed in from outside
++     * @param key2 the second key extracted from the entry via <code>entry.key</code>
++     * @return true if equal
++     */
++    protected boolean isEqualKey(Object key1, Object key2) {
++        //if ((key1 == null) && (key2 != null) || (key1 != null) || (key2 == null)) {
++        //    return false;
++        //}
++        // GenericsNote: Conversion from reference handled by getKey() which replaced all .key references
++        //key2 = (keyType > HARD ? ((Reference) key2).get() : key2);
++        return (key1 == key2 || key1.equals(key2));
++    }
++
++    /**
++     * Creates a ReferenceEntry instead of a HashEntry.
++     *
++     * @param next     the next entry in sequence
++     * @param hashCode the hash code to use
++     * @param key      the key to store
++     * @param value    the value to store
++     * @return the newly created entry
++     */
++    public HashEntry<K, V> createEntry(HashEntry<K, V> next, int hashCode, K key, V value) {
++        return new ReferenceEntry<K, V>(this, (ReferenceEntry<K, V>) next, hashCode, key, value);
++    }
++
++    /**
++     * Creates an entry set iterator.
++     *
++     * @return the entrySet iterator
++     */
++    protected Iterator<Map.Entry<K, V>> createEntrySetIterator() {
++        return new ReferenceEntrySetIterator<K, V>(this);
++    }
++
++    /**
++     * Creates an key set iterator.
++     *
++     * @return the keySet iterator
++     */
++    protected Iterator<K> createKeySetIterator() {
++        return new ReferenceKeySetIterator<K, V>(this);
++    }
++
++    /**
++     * Creates an values iterator.
++     *
++     * @return the values iterator
++     */
++    protected Iterator<V> createValuesIterator() {
++        return new ReferenceValuesIterator<K, V>(this);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * EntrySet implementation.
++     */
++    static class ReferenceEntrySet <K,V> extends EntrySet<K, V> {
++
++        protected ReferenceEntrySet(AbstractHashedMap<K, V> parent) {
++            super(parent);
++        }
++
++        public Object[] toArray() {
++            return toArray(new Object[0]);
++        }
++
++        public <T> T[] toArray(T[] arr) {
++            // special implementation to handle disappearing entries
++            ArrayList<Map.Entry<K, V>> list = new ArrayList<Map.Entry<K, V>>();
++            Iterator<Map.Entry<K, V>> iterator = iterator();
++            while (iterator.hasNext()) {
++                Map.Entry<K, V> e = iterator.next();
++                list.add(new DefaultMapEntry<K, V>(e.getKey(), e.getValue()));
++            }
++            return list.toArray(arr);
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * KeySet implementation.
++     */
++    static class ReferenceKeySet <K,V> extends KeySet<K, V> {
++
++        protected ReferenceKeySet(AbstractHashedMap<K, V> parent) {
++            super(parent);
++        }
++
++        public Object[] toArray() {
++            return toArray(new Object[0]);
++        }
++
++        public <T> T[] toArray(T[] arr) {
++            // special implementation to handle disappearing keys
++            List<K> list = new ArrayList<K>(parent.size());
++            for (Iterator<K> it = iterator(); it.hasNext();) {
++                list.add(it.next());
++            }
++            return list.toArray(arr);
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Values implementation.
++     */
++    static class ReferenceValues <K,V> extends Values<K, V> {
++
++        protected ReferenceValues(AbstractHashedMap<K, V> parent) {
++            super(parent);
++        }
++
++        public Object[] toArray() {
++            return toArray(new Object[0]);
++        }
++
++        public <T> T[] toArray(T[] arr) {
++            // special implementation to handle disappearing values
++            List<V> list = new ArrayList<V>(parent.size());
++            for (Iterator<V> it = iterator(); it.hasNext();) {
++                list.add(it.next());
++            }
++            return list.toArray(arr);
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * A MapEntry implementation for the map.
++     * <p/>
++     * If getKey() or getValue() returns null, it means
++     * the mapping is stale and should be removed.
++     *
++     * @since Commons Collections 3.1
++     */
++    protected static class ReferenceEntry <K,V> extends HashEntry<K, V> {
++        /**
++         * The parent map
++         */
++        protected final AbstractReferenceMap<K, V> parent;
++
++        protected Reference<K> refKey;
++        protected Reference<V> refValue;
++
++        /**
++         * Creates a new entry object for the ReferenceMap.
++         *
++         * @param parent   the parent map
++         * @param next     the next entry in the hash bucket
++         * @param hashCode the hash code of the key
++         * @param key      the key
++         * @param value    the value
++         */
++        public ReferenceEntry(AbstractReferenceMap<K, V> parent, ReferenceEntry<K, V> next, int hashCode, K key, V value) {
++            super(next, hashCode, null, null);
++            this.parent = parent;
++            if (parent.keyType != HARD) {
++                refKey = toReference(parent.keyType, key, hashCode);
++            } else {
++                this.setKey(key);
++            }
++            if (parent.valueType != HARD) {
++                refValue = toReference(parent.valueType, value, hashCode); // the key hashCode is passed in deliberately
++            } else {
++                this.setValue(value);
++            }
++        }
++
++        /**
++         * Gets the key from the entry.
++         * This method dereferences weak and soft keys and thus may return null.
++         *
++         * @return the key, which may be null if it was garbage collected
++         */
++        public K getKey() {
++            return (parent.keyType > HARD) ? refKey.get() : super.getKey();
++        }
++
++        /**
++         * Gets the value from the entry.
++         * This method dereferences weak and soft value and thus may return null.
++         *
++         * @return the value, which may be null if it was garbage collected
++         */
++        public V getValue() {
++            return (parent.valueType > HARD) ? refValue.get() : super.getValue();
++        }
++
++        /**
++         * Sets the value of the entry.
++         *
++         * @param obj the object to store
++         * @return the previous value
++         */
++        public V setValue(V obj) {
++            V old = getValue();
++            if (parent.valueType > HARD) {
++                refValue.clear();
++                refValue = toReference(parent.valueType, obj, hashCode);
++            } else {
++                super.setValue(obj);
++            }
++            return old;
++        }
++
++        /**
++         * Compares this map entry to another.
++         * <p/>
++         * This implementation uses <code>isEqualKey</code> and
++         * <code>isEqualValue</code> on the main map for comparison.
++         *
++         * @param obj the other map entry to compare to
++         * @return true if equal, false if not
++         */
++        public boolean equals(Object obj) {
++            if (obj == this) {
++                return true;
++            }
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++
++            Map.Entry entry = (Map.Entry) obj;
++            Object entryKey = entry.getKey();  // convert to hard reference
++            Object entryValue = entry.getValue();  // convert to hard reference
++            if ((entryKey == null) || (entryValue == null)) {
++                return false;
++            }
++            // compare using map methods, aiding identity subclass
++            // note that key is direct access and value is via method
++            return parent.isEqualKey(entryKey, getKey()) && parent.isEqualValue(entryValue, getValue());
++        }
++
++        /**
++         * Gets the hashcode of the entry using temporary hard references.
++         * <p/>
++         * This implementation uses <code>hashEntry</code> on the main map.
++         *
++         * @return the hashcode of the entry
++         */
++        public int hashCode() {
++            return parent.hashEntry(getKey(), getValue());
++        }
++
++        /**
++         * Constructs a reference of the given type to the given referent.
++         * The reference is registered with the queue for later purging.
++         *
++         * @param type     HARD, SOFT or WEAK
++         * @param referent the object to refer to
++         * @param hash     the hash code of the <i>key</i> of the mapping;
++         *                 this number might be different from referent.hashCode() if
++         *                 the referent represents a value and not a key
++         */
++        protected <T> Reference<T> toReference(int type, T referent, int hash) {
++            switch (type) {
++                case SOFT:
++                    return new SoftRef<T>(hash, referent, parent.queue);
++                case WEAK:
++                    return new WeakRef<T>(hash, referent, parent.queue);
++                default:
++                    throw new Error("Attempt to create hard reference in ReferenceMap!");
++            }
++        }
++
++        /**
++         * Purges the specified reference
++         *
++         * @param ref the reference to purge
++         * @return true or false
++         */
++        boolean purge(Reference ref) {
++            boolean r = (parent.keyType > HARD) && (refKey == ref);
++            r = r || ((parent.valueType > HARD) && (refValue == ref));
++            if (r) {
++                if (parent.keyType > HARD) {
++                    refKey.clear();
++                }
++                if (parent.valueType > HARD) {
++                    refValue.clear();
++                } else if (parent.purgeValues) {
++                    setValue(null);
++                }
++            }
++            return r;
++        }
++
++        /**
++         * Gets the next entry in the bucket.
++         *
++         * @return the next entry in the bucket
++         */
++        protected ReferenceEntry<K, V> next() {
++            return (ReferenceEntry<K, V>) next;
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * The EntrySet iterator.
++     */
++    static class ReferenceIteratorBase <K,V> {
++        /**
++         * The parent map
++         */
++        final AbstractReferenceMap<K, V> parent;
++
++        // These fields keep track of where we are in the table.
++        int index;
++        ReferenceEntry<K, V> entry;
++        ReferenceEntry<K, V> previous;
++
++        // These Object fields provide hard references to the
++        // current and next entry; this assures that if hasNext()
++        // returns true, next() will actually return a valid element.
++        K nextKey;
++        V nextValue;
++        K currentKey;
++        V currentValue;
++
++        int expectedModCount;
++
++        public ReferenceIteratorBase(AbstractReferenceMap<K, V> parent) {
++            super();
++            this.parent = parent;
++            index = (parent.size() != 0 ? parent.data.length : 0);
++            // have to do this here!  size() invocation above
++            // may have altered the modCount.
++            expectedModCount = parent.modCount;
++        }
++
++        public boolean hasNext() {
++            checkMod();
++            while (nextNull()) {
++                ReferenceEntry<K, V> e = entry;
++                int i = index;
++                while ((e == null) && (i > 0)) {
++                    i--;
++                    e = (ReferenceEntry<K, V>) parent.data[i];
++                }
++                entry = e;
++                index = i;
++                if (e == null) {
++                    currentKey = null;
++                    currentValue = null;
++                    return false;
++                }
++                nextKey = e.getKey();
++                nextValue = e.getValue();
++                if (nextNull()) {
++                    entry = entry.next();
++                }
++            }
++            return true;
++        }
++
++        private void checkMod() {
++            if (parent.modCount != expectedModCount) {
++                throw new ConcurrentModificationException();
++            }
++        }
++
++        private boolean nextNull() {
++            return (nextKey == null) || (nextValue == null);
++        }
++
++        protected ReferenceEntry<K, V> nextEntry() {
++            checkMod();
++            if (nextNull() && !hasNext()) {
++                throw new NoSuchElementException();
++            }
++            previous = entry;
++            entry = entry.next();
++            currentKey = nextKey;
++            currentValue = nextValue;
++            nextKey = null;
++            nextValue = null;
++            return previous;
++        }
++
++        protected ReferenceEntry<K, V> currentEntry() {
++            checkMod();
++            return previous;
++        }
++
++        public ReferenceEntry<K, V> superNext() {
++            return nextEntry();
++        }
++
++        public void remove() {
++            checkMod();
++            if (previous == null) {
++                throw new IllegalStateException();
++            }
++            parent.remove(currentKey);
++            previous = null;
++            currentKey = null;
++            currentValue = null;
++            expectedModCount = parent.modCount;
++        }
++    }
++
++    /**
++     * The EntrySet iterator.
++     */
++    static class ReferenceEntrySetIterator <K,V> extends ReferenceIteratorBase<K, V> implements Iterator<Map.Entry<K, V>> {
++
++        public ReferenceEntrySetIterator(AbstractReferenceMap<K, V> abstractReferenceMap) {
++            super(abstractReferenceMap);
++        }
++
++        public ReferenceEntry<K, V> next() {
++            return superNext();
++        }
++
++    }
++
++    /**
++     * The keySet iterator.
++     */
++    static class ReferenceKeySetIterator <K,V> extends ReferenceIteratorBase<K, V> implements Iterator<K> {
++
++        ReferenceKeySetIterator(AbstractReferenceMap<K, V> parent) {
++            super(parent);
++        }
++
++        public K next() {
++            return nextEntry().getKey();
++        }
++    }
++
++    /**
++     * The values iterator.
++     */
++    static class ReferenceValuesIterator <K,V> extends ReferenceIteratorBase<K, V> implements Iterator<V> {
++
++        ReferenceValuesIterator(AbstractReferenceMap<K, V> parent) {
++            super(parent);
++        }
++
++        public V next() {
++            return nextEntry().getValue();
++        }
++    }
++
++    /**
++     * The MapIterator implementation.
++     */
++    static class ReferenceMapIterator <K,V> extends ReferenceIteratorBase<K, V> implements MapIterator<K, V> {
++
++        protected ReferenceMapIterator(AbstractReferenceMap<K, V> parent) {
++            super(parent);
++        }
++
++        public K next() {
++            return nextEntry().getKey();
++        }
++
++        public K getKey() {
++            HashEntry<K, V> current = currentEntry();
++            if (current == null) {
++                throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
++            }
++            return current.getKey();
++        }
++
++        public V getValue() {
++            HashEntry<K, V> current = currentEntry();
++            if (current == null) {
++                throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
++            }
++            return current.getValue();
++        }
++
++        public V setValue(V value) {
++            HashEntry<K, V> current = currentEntry();
++            if (current == null) {
++                throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
++            }
++            return current.setValue(value);
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    // These two classes store the hashCode of the key of
++    // of the mapping, so that after they're dequeued a quick
++    // lookup of the bucket in the table can occur.
++
++    /**
++     * A soft reference holder.
++     */
++    static class SoftRef <T> extends SoftReference<T> {
++        /**
++         * the hashCode of the key (even if the reference points to a value)
++         */
++        private int hash;
++
++        public SoftRef(int hash, T r, ReferenceQueue q) {
++            super(r, q);
++            this.hash = hash;
++        }
++
++        public int hashCode() {
++            return hash;
++        }
++    }
++
++    /**
++     * A weak reference holder.
++     */
++    static class WeakRef <T> extends WeakReference<T> {
++        /**
++         * the hashCode of the key (even if the reference points to a value)
++         */
++        private int hash;
++
++        public WeakRef(int hash, T r, ReferenceQueue q) {
++            super(r, q);
++            this.hash = hash;
++        }
++
++        public int hashCode() {
++            return hash;
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Replaces the superclass method to store the state of this class.
++     * <p/>
++     * Serialization is not one of the JDK's nicest topics. Normal serialization will
++     * initialise the superclass before the subclass. Sometimes however, this isn't
++     * what you want, as in this case the <code>put()</code> method on read can be
++     * affected by subclass state.
++     * <p/>
++     * The solution adopted here is to serialize the state data of this class in
++     * this protected method. This method must be called by the
++     * <code>writeObject()</code> of the first serializable subclass.
++     * <p/>
++     * Subclasses may override if they have a specific field that must be present
++     * on read before this implementation will work. Generally, the read determines
++     * what must be serialized here, if anything.
++     *
++     * @param out the output stream
++     */
++    protected void doWriteObject(ObjectOutputStream out) throws IOException {
++        out.writeInt(keyType);
++        out.writeInt(valueType);
++        out.writeBoolean(purgeValues);
++        out.writeFloat(loadFactor);
++        out.writeInt(data.length);
++        for (MapIterator it = mapIterator(); it.hasNext();) {
++            out.writeObject(it.next());
++            out.writeObject(it.getValue());
++        }
++        out.writeObject(null);  // null terminate map
++        // do not call super.doWriteObject() as code there doesn't work for reference map
++    }
++
++    /**
++     * Replaces the superclassm method to read the state of this class.
++     * <p/>
++     * Serialization is not one of the JDK's nicest topics. Normal serialization will
++     * initialise the superclass before the subclass. Sometimes however, this isn't
++     * what you want, as in this case the <code>put()</code> method on read can be
++     * affected by subclass state.
++     * <p/>
++     * The solution adopted here is to deserialize the state data of this class in
++     * this protected method. This method must be called by the
++     * <code>readObject()</code> of the first serializable subclass.
++     * <p/>
++     * Subclasses may override if the subclass has a specific field that must be present
++     * before <code>put()</code> or <code>calculateThreshold()</code> will work correctly.
++     *
++     * @param in the input stream
++     */
++    protected void doReadObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        this.keyType = in.readInt();
++        this.valueType = in.readInt();
++        this.purgeValues = in.readBoolean();
++        this.loadFactor = in.readFloat();
++        int capacity = in.readInt();
++        init();
++        data = new HashEntry[capacity];
++        while (true) {
++            K key = (K) in.readObject();
++            if (key == null) {
++                break;
++            }
++            V value = (V) in.readObject();
++            put(key, value);
++        }
++        threshold = calculateThreshold(data.length, loadFactor);
++        // do not call super.doReadObject() as code there doesn't work for reference map
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/AbstractSortedMapDecorator.java
+@@ -0,0 +1,93 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import java.util.Comparator;
++import java.util.SortedMap;
++
++/**
++ * Provides a base decorator that enables additional functionality to be added
++ * to a Map via decoration.
++ * <p/>
++ * Methods are forwarded directly to the decorated map.
++ * <p/>
++ * This implementation does not perform any special processing with the map views.
++ * Instead it simply returns the set/collection from the wrapped map. This may be
++ * undesirable, for example if you are trying to write a validating implementation
++ * it would provide a loophole around the validation.
++ * But, you might want that loophole, so this class is kept simple.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractSortedMapDecorator <K,V> extends AbstractMapDecorator<K, V> implements SortedMap<K, V> {
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     *
++     * @since Commons Collections 3.1
++     */
++    protected AbstractSortedMapDecorator() {
++        super();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if the collection is null
++     */
++    public AbstractSortedMapDecorator(SortedMap<K, V> map) {
++        super(map);
++    }
++
++    /**
++     * Gets the map being decorated.
++     *
++     * @return the decorated map
++     */
++    protected SortedMap<K, V> getSortedMap() {
++        return (SortedMap<K, V>) map;
++    }
++
++    //-----------------------------------------------------------------------
++    public Comparator<? super K> comparator() {
++        return getSortedMap().comparator();
++    }
++
++    public K firstKey() {
++        return getSortedMap().firstKey();
++    }
++
++    public SortedMap<K, V> headMap(K toKey) {
++        return getSortedMap().headMap(toKey);
++    }
++
++    public K lastKey() {
++        return getSortedMap().lastKey();
++    }
++
++    public SortedMap<K, V> subMap(K fromKey, K toKey) {
++        return getSortedMap().subMap(fromKey, toKey);
++    }
++
++    public SortedMap<K, V> tailMap(K fromKey) {
++        return getSortedMap().tailMap(fromKey);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/CaseInsensitiveMap.java
+@@ -0,0 +1,168 @@
++// GenericsNote: Converted -- refactored heavily, and now must be a map of String -> ?.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Iterator;
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * A case-insensitive <code>Map</code>.
++ * <p/>
++ * As entries are added to the map, keys are converted to all lowercase. A new
++ * key is compared to existing keys by comparing <code>newKey.toLower()</code>
++ * to the lowercase values in the current <code>KeySet.</code>
++ * <p/>
++ * Null keys are supported.
++ * <p/>
++ * The <code>keySet()</code> method returns all lowercase keys, or nulls.
++ * <p/>
++ * Example:
++ * <pre><code>
++ *  Map map = new CaseInsensitiveMap();
++ *  map.put("One", "One");
++ *  map.put("Two", "Two");
++ *  map.put(null, "Three");
++ *  map.put("one", "Four");
++ * </code></pre>
++ * creates a <code>CaseInsensitiveMap</code> with three entries.<br>
++ * <code>map.get(null)</code> returns <code>"Three"</code> and <code>map.get("ONE")</code>
++ * returns <code>"Four".</code>  The <code>Set</code> returned by <code>keySet()</code>
++ * equals <code>{"one", "two", null}.</code>
++ *
++ * @author Matt Hall, John Watkinson, Commons-Collections team
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class CaseInsensitiveMap <V> extends AbstractHashedMap<String, V> implements Serializable, Cloneable {
++
++    /**
++     * Serialisation version
++     */
++    private static final long serialVersionUID = -7074655917369299456L;
++
++    /**
++     * Constructs a new empty map with default size and load factor.
++     */
++    public CaseInsensitiveMap() {
++        super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity.
++     *
++     * @param initialCapacity the initial capacity
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     */
++    public CaseInsensitiveMap(int initialCapacity) {
++        super(initialCapacity);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity and
++     * load factor.
++     *
++     * @param initialCapacity the initial capacity
++     * @param loadFactor      the load factor
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     * @throws IllegalArgumentException if the load factor is less than zero
++     */
++    public CaseInsensitiveMap(int initialCapacity, float loadFactor) {
++        super(initialCapacity, loadFactor);
++    }
++
++    /**
++     * Constructor copying elements from another map.
++     * <p/>
++     * Keys will be converted to lower case strings, which may cause
++     * some entries to be removed (if string representation of keys differ
++     * only by character case).
++     *
++     * @param map the map to copy
++     * @throws NullPointerException if the map is null
++     */
++    public CaseInsensitiveMap(Map<? extends String, ? extends V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Converts keys to lower case.
++     * <p/>
++     * Returns null if key is null.
++     *
++     * @param key the key convert
++     * @return the converted key
++     */
++    protected String convertKey(String key) {
++        if (key != null) {
++            return key.toString().toLowerCase();
++        } else {
++            return null;
++        }
++    }
++
++    @Override public V get(Object key) {
++        if (!(key instanceof String)) {
++            return super.get(key);
++        }
++        return super.get(convertKey((String) key));
++    }
++
++    @Override public V put(String s, V v) {
++        return super.put(convertKey(s), v);
++    }
++
++    @Override public void putAll(Map<? extends String, ? extends V> map) {
++        Set entries = map.entrySet();
++        for (Iterator<Entry<? extends String, ? extends V>> iterator = entries.iterator(); iterator.hasNext();) {
++            Entry<? extends String, ? extends V> entry = iterator.next();
++            put(entry.getKey(), entry.getValue());
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Clones the map without cloning the keys or values.
++     *
++     * @return a shallow clone
++     */
++    public Object clone() {
++        return super.clone();
++    }
++
++    /**
++     * Write the map out using a custom routine.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        doWriteObject(out);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        doReadObject(in);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/CompositeMap.java
+@@ -0,0 +1,523 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.CollectionUtils;
++import org.apache.commons.collections15.collection.CompositeCollection;
++import org.apache.commons.collections15.set.CompositeSet;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * Decorates a map of other maps to provide a single unified view.
++ * <p/>
++ * Changes made to this map will actually be made on the decorated map.
++ * Add and remove operations require the use of a pluggable strategy. If no
++ * strategy is provided then add and remove are unsupported.
++ *
++ * @author Matt Hall, John Watkinson, Brian McCallister
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class CompositeMap <K,V> implements Map<K, V> {
++
++    /**
++     * Array of all maps in the composite
++     */
++    private Map[] composite;
++
++    /**
++     * Handle mutation operations
++     */
++    private MapMutator<K, V> mutator;
++
++    /**
++     * Create a new, empty, CompositeMap.
++     */
++    public CompositeMap() {
++        this(new Map[]{}, null);
++    }
++
++    /**
++     * Create a new CompositeMap with two composited Map instances.
++     *
++     * @param one the first Map to be composited
++     * @param two the second Map to be composited
++     * @throws IllegalArgumentException if there is a key collision
++     */
++    public CompositeMap(Map<? extends K, ? extends V> one, Map<? extends K, ? extends V> two) {
++        this(new Map[]{one, two}, null);
++    }
++
++    /**
++     * Create a new CompositeMap with two composited Map instances.
++     *
++     * @param one     the first Map to be composited
++     * @param two     the second Map to be composited
++     * @param mutator MapMutator to be used for mutation operations
++     */
++    public CompositeMap(Map<? extends K, ? extends V> one, Map<? extends K, ? extends V> two, MapMutator<K, V> mutator) {
++        this(new Map[]{one, two}, mutator);
++    }
++
++    /**
++     * Create a new CompositeMap which composites all of the Map instances in the
++     * argument. It copies the argument array, it does not use it directly.
++     *
++     * @param composite the Maps to be composited
++     * @throws IllegalArgumentException if there is a key collision
++     */
++    public CompositeMap(Map[] composite) {
++        this(composite, null);
++    }
++
++    /**
++     * Create a new CompositeMap which composites all of the Map instances in the
++     * argument. It copies the argument array, it does not use it directly.
++     *
++     * @param composite Maps to be composited
++     * @param mutator   MapMutator to be used for mutation operations
++     */
++    public CompositeMap(Map[] composite, MapMutator<K, V> mutator) {
++        this.mutator = mutator;
++        this.composite = new Map[0];
++        for (int i = composite.length - 1; i >= 0; --i) {
++            this.addComposited(composite[i]);
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Specify the MapMutator to be used by mutation operations.
++     *
++     * @param mutator the MapMutator to be used for mutation delegation
++     */
++    public void setMutator(MapMutator<K, V> mutator) {
++        this.mutator = mutator;
++    }
++
++    /**
++     * Add an additional Map to the composite.
++     *
++     * @param map the Map to be added to the composite
++     * @throws IllegalArgumentException if there is a key collision and there is no
++     *                                  MapMutator set to handle it.
++     */
++    public synchronized void addComposited(Map<? extends K, ? extends V> map) throws IllegalArgumentException {
++        for (int i = composite.length - 1; i >= 0; --i) {
++            Collection<K> intersect = (Collection<K>) CollectionUtils.intersection(this.composite[i].keySet(), map.keySet());
++            if (intersect.size() != 0) {
++                if (this.mutator == null) {
++                    throw new IllegalArgumentException("Key collision adding Map to CompositeMap");
++                } else {
++                    this.mutator.resolveCollision(this, this.composite[i], map, intersect);
++                }
++            }
++        }
++        Map[] temp = new Map[this.composite.length + 1];
++        System.arraycopy(this.composite, 0, temp, 0, this.composite.length);
++        temp[temp.length - 1] = map;
++        this.composite = temp;
++    }
++
++    /**
++     * Remove a Map from the composite.
++     *
++     * @param map the Map to be removed from the composite
++     * @return The removed Map or <code>null</code> if map is not in the composite
++     */
++    public synchronized Map<? extends K, ? extends V> removeComposited(Map<? extends K, ? extends V> map) {
++        int size = this.composite.length;
++        for (int i = 0; i < size; ++i) {
++            if (this.composite[i].equals(map)) {
++                Map[] temp = new Map[size - 1];
++                System.arraycopy(this.composite, 0, temp, 0, i);
++                System.arraycopy(this.composite, i + 1, temp, i, size - i - 1);
++                this.composite = temp;
++                return map;
++            }
++        }
++        return null;
++    }
++
++    //-----------------------------------------------------------------------    
++    /**
++     * Calls <code>clear()</code> on all composited Maps.
++     *
++     * @throws UnsupportedOperationException if any of the composited Maps do not support clear()
++     */
++    public void clear() {
++        for (int i = this.composite.length - 1; i >= 0; --i) {
++            this.composite[i].clear();
++        }
++    }
++
++    /**
++     * Returns <tt>true</tt> if this map contains a mapping for the specified
++     * key.  More formally, returns <tt>true</tt> if and only if
++     * this map contains at a mapping for a key <tt>k</tt> such that
++     * <tt>(key==null ? k==null : key.equals(k))</tt>.  (There can be
++     * at most one such mapping.)
++     *
++     * @param key key whose presence in this map is to be tested.
++     * @return <tt>true</tt> if this map contains a mapping for the specified
++     *         key.
++     * @throws ClassCastException   if the key is of an inappropriate type for
++     *                              this map (optional).
++     * @throws NullPointerException if the key is <tt>null</tt> and this map
++     *                              does not not permit <tt>null</tt> keys (optional).
++     */
++    public boolean containsKey(Object key) {
++        for (int i = this.composite.length - 1; i >= 0; --i) {
++            if (this.composite[i].containsKey(key)) {
++                return true;
++            }
++        }
++        return false;
++    }
++
++    /**
++     * Returns <tt>true</tt> if this map maps one or more keys to the
++     * specified value.  More formally, returns <tt>true</tt> if and only if
++     * this map contains at least one mapping to a value <tt>v</tt> such that
++     * <tt>(value==null ? v==null : value.equals(v))</tt>.  This operation
++     * will probably require time linear in the map size for most
++     * implementations of the <tt>Map</tt> interface.
++     *
++     * @param value value whose presence in this map is to be tested.
++     * @return <tt>true</tt> if this map maps one or more keys to the
++     *         specified value.
++     * @throws ClassCastException   if the value is of an inappropriate type for
++     *                              this map (optional).
++     * @throws NullPointerException if the value is <tt>null</tt> and this map
++     *                              does not not permit <tt>null</tt> values (optional).
++     */
++    public boolean containsValue(Object value) {
++        for (int i = this.composite.length - 1; i >= 0; --i) {
++            if (this.composite[i].containsValue(value)) {
++                return true;
++            }
++        }
++        return false;
++    }
++
++    /**
++     * Returns a set view of the mappings contained in this map.  Each element
++     * in the returned set is a <code>Map.Entry</code>.  The set is backed by the
++     * map, so changes to the map are reflected in the set, and vice-versa.
++     * If the map is modified while an iteration over the set is in progress,
++     * the results of the iteration are undefined.  The set supports element
++     * removal, which removes the corresponding mapping from the map, via the
++     * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>, <tt>removeAll</tt>,
++     * <tt>retainAll</tt> and <tt>clear</tt> operations.  It does not support
++     * the <tt>add</tt> or <tt>addAll</tt> operations.
++     * <p/>
++     * This implementation returns a <code>CompositeSet</code> which
++     * composites the entry sets from all of the composited maps.
++     *
++     * @return a set view of the mappings contained in this map.
++     * @see CompositeSet
++     */
++    public Set entrySet() {
++        CompositeSet<Map.Entry<K, V>> entries = new CompositeSet<Map.Entry<K, V>>();
++        for (int i = this.composite.length - 1; i >= 0; --i) {
++            entries.addComposited(this.composite[i].entrySet());
++        }
++        return entries;
++    }
++
++    /**
++     * Returns the value to which this map maps the specified key.  Returns
++     * <tt>null</tt> if the map contains no mapping for this key.  A return
++     * value of <tt>null</tt> does not <i>necessarily</i> indicate that the
++     * map contains no mapping for the key; it's also possible that the map
++     * explicitly maps the key to <tt>null</tt>.  The <tt>containsKey</tt>
++     * operation may be used to distinguish these two cases.
++     * <p/>
++     * <p>More formally, if this map contains a mapping from a key
++     * <tt>k</tt> to a value <tt>v</tt> such that <tt>(key==null ? k==null :
++     * key.equals(k))</tt>, then this method returns <tt>v</tt>; otherwise
++     * it returns <tt>null</tt>.  (There can be at most one such mapping.)
++     *
++     * @param key key whose associated value is to be returned.
++     * @return the value to which this map maps the specified key, or
++     *         <tt>null</tt> if the map contains no mapping for this key.
++     * @throws ClassCastException   if the key is of an inappropriate type for
++     *                              this map (optional).
++     * @throws NullPointerException key is <tt>null</tt> and this map does not
++     *                              not permit <tt>null</tt> keys (optional).
++     * @see #containsKey(Object)
++     */
++    public V get(Object key) {
++        for (int i = this.composite.length - 1; i >= 0; --i) {
++            if (this.composite[i].containsKey(key)) {
++                return (V) this.composite[i].get(key);
++            }
++        }
++        return null;
++    }
++
++    /**
++     * Returns <tt>true</tt> if this map contains no key-value mappings.
++     *
++     * @return <tt>true</tt> if this map contains no key-value mappings.
++     */
++    public boolean isEmpty() {
++        for (int i = this.composite.length - 1; i >= 0; --i) {
++            if (!this.composite[i].isEmpty()) {
++                return false;
++            }
++        }
++        return true;
++    }
++
++    /**
++     * Returns a set view of the keys contained in this map.  The set is
++     * backed by the map, so changes to the map are reflected in the set, and
++     * vice-versa.  If the map is modified while an iteration over the set is
++     * in progress, the results of the iteration are undefined.  The set
++     * supports element removal, which removes the corresponding mapping from
++     * the map, via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
++     * <tt>removeAll</tt> <tt>retainAll</tt>, and <tt>clear</tt> operations.
++     * It does not support the add or <tt>addAll</tt> operations.
++     * <p/>
++     * This implementation returns a <code>CompositeSet</code> which
++     * composites the key sets from all of the composited maps.
++     *
++     * @return a set view of the keys contained in this map.
++     */
++    public Set keySet() {
++        CompositeSet<K> keys = new CompositeSet<K>();
++        for (int i = this.composite.length - 1; i >= 0; --i) {
++            keys.addComposited(this.composite[i].keySet());
++        }
++        return keys;
++    }
++
++    /**
++     * Associates the specified value with the specified key in this map
++     * (optional operation).  If the map previously contained a mapping for
++     * this key, the old value is replaced by the specified value.  (A map
++     * <tt>m</tt> is said to contain a mapping for a key <tt>k</tt> if and only
++     * if {@link #containsKey(Object) m.containsKey(k)} would return
++     * <tt>true</tt>.))
++     *
++     * @param key   key with which the specified value is to be associated.
++     * @param value value to be associated with the specified key.
++     * @return previous value associated with specified key, or <tt>null</tt>
++     *         if there was no mapping for key.  A <tt>null</tt> return can
++     *         also indicate that the map previously associated <tt>null</tt>
++     *         with the specified key, if the implementation supports
++     *         <tt>null</tt> values.
++     * @throws UnsupportedOperationException if no MapMutator has been specified
++     * @throws ClassCastException            if the class of the specified key or value
++     *                                       prevents it from being stored in this map.
++     * @throws IllegalArgumentException      if some aspect of this key or value
++     *                                       prevents it from being stored in this map.
++     * @throws NullPointerException          this map does not permit <tt>null</tt>
++     *                                       keys or values, and the specified key or value is
++     *                                       <tt>null</tt>.
++     */
++    public V put(K key, V value) {
++        if (this.mutator == null) {
++            throw new UnsupportedOperationException("No mutator specified");
++        }
++        return this.mutator.put(this, this.composite, key, value);
++    }
++
++    /**
++     * Copies all of the mappings from the specified map to this map
++     * (optional operation).  The effect of this call is equivalent to that
++     * of calling {@link #put(Object,Object) put(k, v)} on this map once
++     * for each mapping from key <tt>k</tt> to value <tt>v</tt> in the
++     * specified map.  The behavior of this operation is unspecified if the
++     * specified map is modified while the operation is in progress.
++     *
++     * @param map Mappings to be stored in this map.
++     * @throws UnsupportedOperationException if the <tt>putAll</tt> method is
++     *                                       not supported by this map.
++     * @throws ClassCastException            if the class of a key or value in the
++     *                                       specified map prevents it from being stored in this map.
++     * @throws IllegalArgumentException      some aspect of a key or value in the
++     *                                       specified map prevents it from being stored in this map.
++     * @throws NullPointerException          the specified map is <tt>null</tt>, or if
++     *                                       this map does not permit <tt>null</tt> keys or values, and the
++     *                                       specified map contains <tt>null</tt> keys or values.
++     */
++    public void putAll(Map<? extends K, ? extends V> map) {
++        if (this.mutator == null) {
++            throw new UnsupportedOperationException("No mutator specified");
++        }
++        this.mutator.putAll(this, this.composite, map);
++    }
++
++    /**
++     * Removes the mapping for this key from this map if it is present
++     * (optional operation).   More formally, if this map contains a mapping
++     * from key <tt>k</tt> to value <tt>v</tt> such that
++     * <code>(key==null ?  k==null : key.equals(k))</code>, that mapping
++     * is removed.  (The map can contain at most one such mapping.)
++     * <p/>
++     * <p>Returns the value to which the map previously associated the key, or
++     * <tt>null</tt> if the map contained no mapping for this key.  (A
++     * <tt>null</tt> return can also indicate that the map previously
++     * associated <tt>null</tt> with the specified key if the implementation
++     * supports <tt>null</tt> values.)  The map will not contain a mapping for
++     * the specified  key once the call returns.
++     *
++     * @param key key whose mapping is to be removed from the map.
++     * @return previous value associated with specified key, or <tt>null</tt>
++     *         if there was no mapping for key.
++     * @throws ClassCastException            if the key is of an inappropriate type for
++     *                                       the composited map (optional).
++     * @throws NullPointerException          if the key is <tt>null</tt> and the composited map
++     *                                       does not not permit <tt>null</tt> keys (optional).
++     * @throws UnsupportedOperationException if the <tt>remove</tt> method is
++     *                                       not supported by the composited map containing the key
++     */
++    public V remove(Object key) {
++        for (int i = this.composite.length - 1; i >= 0; --i) {
++            if (this.composite[i].containsKey(key)) {
++                return (V) this.composite[i].remove(key);
++            }
++        }
++        return null;
++    }
++
++    /**
++     * Returns the number of key-value mappings in this map.  If the
++     * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
++     * <tt>Integer.MAX_VALUE</tt>.
++     *
++     * @return the number of key-value mappings in this map.
++     */
++    public int size() {
++        int size = 0;
++        for (int i = this.composite.length - 1; i >= 0; --i) {
++            size += this.composite[i].size();
++        }
++        return size;
++    }
++
++    /**
++     * Returns a collection view of the values contained in this map.  The
++     * collection is backed by the map, so changes to the map are reflected in
++     * the collection, and vice-versa.  If the map is modified while an
++     * iteration over the collection is in progress, the results of the
++     * iteration are undefined.  The collection supports element removal,
++     * which removes the corresponding mapping from the map, via the
++     * <tt>Iterator.remove</tt>, <tt>Collection.remove</tt>,
++     * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt> operations.
++     * It does not support the add or <tt>addAll</tt> operations.
++     *
++     * @return a collection view of the values contained in this map.
++     */
++    public Collection<V> values() {
++        CompositeCollection<V> keys = new CompositeCollection<V>();
++        for (int i = this.composite.length - 1; i >= 0; --i) {
++            keys.addComposited(this.composite[i].values());
++        }
++        return keys;
++    }
++
++    /**
++     * Checks if this Map equals another as per the Map specification.
++     *
++     * @param obj the object to compare to
++     * @return true if the maps are equal
++     */
++    public boolean equals(Object obj) {
++        if (obj instanceof Map) {
++            Map map = (Map) obj;
++            return (this.entrySet().equals(map.entrySet()));
++        }
++        return false;
++    }
++
++    /**
++     * Gets a hash code for the Map as per the Map specification.
++     */
++    public int hashCode() {
++        int code = 0;
++        for (Iterator i = this.entrySet().iterator(); i.hasNext();) {
++            code += i.next().hashCode();
++        }
++        return code;
++    }
++
++    /**
++     * This interface allows definition for all of the indeterminate
++     * mutators in a CompositeMap, as well as providing a hook for
++     * callbacks on key collisions.
++     */
++    public static interface MapMutator <K,V> {
++        /**
++         * Called when adding a new Composited Map results in a
++         * key collision.
++         *
++         * @param composite the CompositeMap with the collision
++         * @param existing  the Map already in the composite which contains the
++         *                  offending key
++         * @param added     the Map being added
++         * @param intersect the intersection of the keysets of the existing and added maps
++         */
++        public void resolveCollision(CompositeMap<K, V> composite, Map<? extends K, ? extends V> existing, Map<? extends K, ? extends V> added, Collection<K> intersect);
++
++        /**
++         * Called when the CompositeMap.put() method is invoked.
++         *
++         * @param map        the CompositeMap which is being modified
++         * @param composited array of Maps in the CompositeMap being modified
++         * @param key        key with which the specified value is to be associated.
++         * @param value      value to be associated with the specified key.
++         * @return previous value associated with specified key, or <tt>null</tt>
++         *         if there was no mapping for key.  A <tt>null</tt> return can
++         *         also indicate that the map previously associated <tt>null</tt>
++         *         with the specified key, if the implementation supports
++         *         <tt>null</tt> values.
++         * @throws UnsupportedOperationException if not defined
++         * @throws ClassCastException            if the class of the specified key or value
++         *                                       prevents it from being stored in this map.
++         * @throws IllegalArgumentException      if some aspect of this key or value
++         *                                       prevents it from being stored in this map.
++         * @throws NullPointerException          this map does not permit <tt>null</tt>
++         *                                       keys or values, and the specified key or value is
++         *                                       <tt>null</tt>.
++         */
++        public V put(CompositeMap<K, V> map, Map[] composited, K key, V value);
++
++        /**
++         * Called when the CompositeMap.putAll() method is invoked.
++         *
++         * @param map        the CompositeMap which is being modified
++         * @param composited array of Maps in the CompositeMap being modified
++         * @param mapToAdd   Mappings to be stored in this CompositeMap
++         * @throws UnsupportedOperationException if not defined
++         * @throws ClassCastException            if the class of the specified key or value
++         *                                       prevents it from being stored in this map.
++         * @throws IllegalArgumentException      if some aspect of this key or value
++         *                                       prevents it from being stored in this map.
++         * @throws NullPointerException          this map does not permit <tt>null</tt>
++         *                                       keys or values, and the specified key or value is
++         *                                       <tt>null</tt>.
++         */
++        public void putAll(CompositeMap<K, V> map, Map[] composited, Map<? extends K, ? extends V> mapToAdd);
++    }
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/FastHashMap.java
+@@ -0,0 +1,711 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import java.util.*;
++
++/**
++ * <p>A customized implementation of <code>java.util.HashMap</code> designed
++ * to operate in a multithreaded environment where the large majority of
++ * method calls are read-only, instead of structural changes.  When operating
++ * in "fast" mode, read calls are non-synchronized and write calls perform the
++ * following steps:</p>
++ * <ul>
++ * <li>Clone the existing collection
++ * <li>Perform the modification on the clone
++ * <li>Replace the existing collection with the (modified) clone
++ * </ul>
++ * <p>When first created, objects of this class default to "slow" mode, where
++ * all accesses of any type are synchronized but no cloning takes place.  This
++ * is appropriate for initially populating the collection, followed by a switch
++ * to "fast" mode (by calling <code>setFast(true)</code>) after initialization
++ * is complete.</p>
++ * <p/>
++ * <p><strong>NOTE</strong>: If you are creating and accessing a
++ * <code>HashMap</code> only within a single thread, you should use
++ * <code>java.util.HashMap</code> directly (with no synchronization), for
++ * maximum performance.</p>
++ * <p/>
++ * <p><strong>NOTE</strong>: <i>This class is not cross-platform.
++ * Using it may cause unexpected failures on some architectures.</i>
++ * It suffers from the same problems as the double-checked locking idiom.
++ * In particular, the instruction that clones the internal collection and the
++ * instruction that sets the internal reference to the clone can be executed
++ * or perceived out-of-order.  This means that any read operation might fail
++ * unexpectedly, as it may be reading the state of the internal collection
++ * before the internal collection is fully formed.
++ * For more information on the double-checked locking idiom, see the
++ * <a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html">
++ * Double-Checked Locking Idiom Is Broken Declaration</a>.</p>
++ *
++ * @author Craig R. McClanahan
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 1.0
++ */
++public class FastHashMap <K,V> extends HashMap<K, V> {
++
++    /**
++     * The underlying map we are managing.
++     */
++    protected HashMap<K, V> map = null;
++
++    /**
++     * Are we currently operating in "fast" mode?
++     */
++    protected boolean fast = false;
++
++    // Constructors
++    // ----------------------------------------------------------------------
++
++    /**
++     * Construct an empty map.
++     */
++    public FastHashMap() {
++        super();
++        this.map = new HashMap<K, V>();
++    }
++
++    /**
++     * Construct an empty map with the specified capacity.
++     *
++     * @param capacity the initial capacity of the empty map
++     */
++    public FastHashMap(int capacity) {
++        super();
++        this.map = new HashMap<K, V>(capacity);
++    }
++
++    /**
++     * Construct an empty map with the specified capacity and load factor.
++     *
++     * @param capacity the initial capacity of the empty map
++     * @param factor   the load factor of the new map
++     */
++    public FastHashMap(int capacity, float factor) {
++        super();
++        this.map = new HashMap<K, V>(capacity, factor);
++    }
++
++    /**
++     * Construct a new map with the same mappings as the specified map.
++     *
++     * @param map the map whose mappings are to be copied
++     */
++    public FastHashMap(Map map) {
++        super();
++        this.map = new HashMap<K, V>(map);
++    }
++
++
++    // Property access
++    // ----------------------------------------------------------------------
++
++    /**
++     * Returns true if this map is operating in fast mode.
++     *
++     * @return true if this map is operating in fast mode
++     */
++    public boolean getFast() {
++        return (this.fast);
++    }
++
++    /**
++     * Sets whether this map is operating in fast mode.
++     *
++     * @param fast true if this map should operate in fast mode
++     */
++    public void setFast(boolean fast) {
++        this.fast = fast;
++    }
++
++
++    // Map access
++    // ----------------------------------------------------------------------
++    // These methods can forward straight to the wrapped Map in 'fast' mode.
++    // (because they are query methods)
++
++    /**
++     * Return the value to which this map maps the specified key.  Returns
++     * <code>null</code> if the map contains no mapping for this key, or if
++     * there is a mapping with a value of <code>null</code>.  Use the
++     * <code>containsKey()</code> method to disambiguate these cases.
++     *
++     * @param key the key whose value is to be returned
++     * @return the value mapped to that key, or null
++     */
++    public V get(Object key) {
++        if (fast) {
++            return (map.get(key));
++        } else {
++            synchronized (map) {
++                return (map.get(key));
++            }
++        }
++    }
++
++    /**
++     * Return the number of key-value mappings in this map.
++     *
++     * @return the current size of the map
++     */
++    public int size() {
++        if (fast) {
++            return (map.size());
++        } else {
++            synchronized (map) {
++                return (map.size());
++            }
++        }
++    }
++
++    /**
++     * Return <code>true</code> if this map contains no mappings.
++     *
++     * @return is the map currently empty
++     */
++    public boolean isEmpty() {
++        if (fast) {
++            return (map.isEmpty());
++        } else {
++            synchronized (map) {
++                return (map.isEmpty());
++            }
++        }
++    }
++
++    /**
++     * Return <code>true</code> if this map contains a mapping for the
++     * specified key.
++     *
++     * @param key the key to be searched for
++     * @return true if the map contains the key
++     */
++    public boolean containsKey(Object key) {
++        if (fast) {
++            return (map.containsKey(key));
++        } else {
++            synchronized (map) {
++                return (map.containsKey(key));
++            }
++        }
++    }
++
++    /**
++     * Return <code>true</code> if this map contains one or more keys mapping
++     * to the specified value.
++     *
++     * @param value the value to be searched for
++     * @return true if the map contains the value
++     */
++    public boolean containsValue(Object value) {
++        if (fast) {
++            return (map.containsValue(value));
++        } else {
++            synchronized (map) {
++                return (map.containsValue(value));
++            }
++        }
++    }
++
++    // Map modification
++    // ----------------------------------------------------------------------
++    // These methods perform special behaviour in 'fast' mode.
++    // The map is cloned, updated and then assigned back.
++    // See the comments at the top as to why this won't always work.
++
++    /**
++     * Associate the specified value with the specified key in this map.
++     * If the map previously contained a mapping for this key, the old
++     * value is replaced and returned.
++     *
++     * @param key   the key with which the value is to be associated
++     * @param value the value to be associated with this key
++     * @return the value previously mapped to the key, or null
++     */
++    public V put(K key, V value) {
++        if (fast) {
++            synchronized (this) {
++                HashMap<K, V> temp = (HashMap<K, V>) map.clone();
++                V result = temp.put(key, value);
++                map = temp;
++                return (result);
++            }
++        } else {
++            synchronized (map) {
++                return (map.put(key, value));
++            }
++        }
++    }
++
++    /**
++     * Copy all of the mappings from the specified map to this one, replacing
++     * any mappings with the same keys.
++     *
++     * @param in the map whose mappings are to be copied
++     */
++    public void putAll(Map<? extends K, ? extends V> in) {
++        if (fast) {
++            synchronized (this) {
++                HashMap<K, V> temp = (HashMap<K, V>) map.clone();
++                temp.putAll(in);
++                map = temp;
++            }
++        } else {
++            synchronized (map) {
++                map.putAll(in);
++            }
++        }
++    }
++
++    /**
++     * Remove any mapping for this key, and return any previously
++     * mapped value.
++     *
++     * @param key the key whose mapping is to be removed
++     * @return the value removed, or null
++     */
++    public V remove(Object key) {
++        if (fast) {
++            synchronized (this) {
++                HashMap<K, V> temp = (HashMap<K, V>) map.clone();
++                V result = temp.remove(key);
++                map = temp;
++                return (result);
++            }
++        } else {
++            synchronized (map) {
++                return (map.remove(key));
++            }
++        }
++    }
++
++    /**
++     * Remove all mappings from this map.
++     */
++    public void clear() {
++        if (fast) {
++            synchronized (this) {
++                map = new HashMap<K, V>();
++            }
++        } else {
++            synchronized (map) {
++                map.clear();
++            }
++        }
++    }
++
++    // Basic object methods
++    // ----------------------------------------------------------------------
++    
++    /**
++     * Compare the specified object with this list for equality.  This
++     * implementation uses exactly the code that is used to define the
++     * list equals function in the documentation for the
++     * <code>Map.equals</code> method.
++     *
++     * @param o the object to be compared to this list
++     * @return true if the two maps are equal
++     */
++    public boolean equals(Object o) {
++        // Simple tests that require no synchronization
++        if (o == this) {
++            return (true);
++        } else if (!(o instanceof Map)) {
++            return (false);
++        }
++        Map mo = (Map) o;
++
++        // Compare the two maps for equality
++        if (fast) {
++            if (mo.size() != map.size()) {
++                return (false);
++            }
++            Iterator i = map.entrySet().iterator();
++            while (i.hasNext()) {
++                Map.Entry e = (Map.Entry) i.next();
++                Object key = e.getKey();
++                Object value = e.getValue();
++                if (value == null) {
++                    if (!(mo.get(key) == null && mo.containsKey(key))) {
++                        return (false);
++                    }
++                } else {
++                    if (!value.equals(mo.get(key))) {
++                        return (false);
++                    }
++                }
++            }
++            return (true);
++
++        } else {
++            synchronized (map) {
++                if (mo.size() != map.size()) {
++                    return (false);
++                }
++                Iterator i = map.entrySet().iterator();
++                while (i.hasNext()) {
++                    Map.Entry e = (Map.Entry) i.next();
++                    Object key = e.getKey();
++                    Object value = e.getValue();
++                    if (value == null) {
++                        if (!(mo.get(key) == null && mo.containsKey(key))) {
++                            return (false);
++                        }
++                    } else {
++                        if (!value.equals(mo.get(key))) {
++                            return (false);
++                        }
++                    }
++                }
++                return (true);
++            }
++        }
++    }
++
++    /**
++     * Return the hash code value for this map.  This implementation uses
++     * exactly the code that is used to define the list hash function in the
++     * documentation for the <code>Map.hashCode</code> method.
++     *
++     * @return suitable integer hash code
++     */
++    public int hashCode() {
++        if (fast) {
++            int h = 0;
++            Iterator<Map.Entry<K, V>> i = map.entrySet().iterator();
++            while (i.hasNext()) {
++                h += i.next().hashCode();
++            }
++            return (h);
++        } else {
++            synchronized (map) {
++                int h = 0;
++                Iterator<Map.Entry<K, V>> i = map.entrySet().iterator();
++                while (i.hasNext()) {
++                    h += i.next().hashCode();
++                }
++                return (h);
++            }
++        }
++    }
++
++    /**
++     * Return a shallow copy of this <code>FastHashMap</code> instance.
++     * The keys and values themselves are not copied.
++     *
++     * @return a clone of this map
++     */
++    public FastHashMap<K, V> clone() {
++        FastHashMap<K, V> results = null;
++        if (fast) {
++            results = new FastHashMap<K, V>(map);
++        } else {
++            synchronized (map) {
++                results = new FastHashMap<K, V>(map);
++            }
++        }
++        results.setFast(getFast());
++        return (results);
++    }
++
++    // Map views
++    // ----------------------------------------------------------------------
++    
++    /**
++     * Return a collection view of the mappings contained in this map.  Each
++     * element in the returned collection is a <code>Map.Entry</code>.
++     */
++    public Set<Map.Entry<K, V>> entrySet() {
++        return new EntrySet();
++    }
++
++    /**
++     * Return a set view of the keys contained in this map.
++     */
++    public Set<K> keySet() {
++        return new KeySet();
++    }
++
++    /**
++     * Return a collection view of the values contained in this map.
++     */
++    public Collection<V> values() {
++        return new Values();
++    }
++
++    // Map view inner classes
++    // ----------------------------------------------------------------------
++
++    /**
++     * Abstract collection implementation shared by keySet(), values() and entrySet().
++     */
++    private abstract class CollectionView <E> implements Collection<E> {
++
++        public CollectionView() {
++        }
++
++        protected abstract Collection<E> get(Map<K, V> map);
++
++        protected abstract E iteratorNext(Map.Entry<K, V> entry);
++
++
++        public void clear() {
++            if (fast) {
++                synchronized (FastHashMap.this) {
++                    map = new HashMap<K, V>();
++                }
++            } else {
++                synchronized (map) {
++                    get(map).clear();
++                }
++            }
++        }
++
++        public boolean remove(Object o) {
++            if (fast) {
++                synchronized (FastHashMap.this) {
++                    HashMap temp = (HashMap) map.clone();
++                    boolean r = get(temp).remove(o);
++                    map = temp;
++                    return r;
++                }
++            } else {
++                synchronized (map) {
++                    return get(map).remove(o);
++                }
++            }
++        }
++
++        public boolean removeAll(Collection<?> o) {
++            if (fast) {
++                synchronized (FastHashMap.this) {
++                    HashMap temp = (HashMap) map.clone();
++                    boolean r = get(temp).removeAll(o);
++                    map = temp;
++                    return r;
++                }
++            } else {
++                synchronized (map) {
++                    return get(map).removeAll(o);
++                }
++            }
++        }
++
++        public boolean retainAll(Collection<?> o) {
++            if (fast) {
++                synchronized (FastHashMap.this) {
++                    HashMap temp = (HashMap) map.clone();
++                    boolean r = get(temp).retainAll(o);
++                    map = temp;
++                    return r;
++                }
++            } else {
++                synchronized (map) {
++                    return get(map).retainAll(o);
++                }
++            }
++        }
++
++        public int size() {
++            if (fast) {
++                return get(map).size();
++            } else {
++                synchronized (map) {
++                    return get(map).size();
++                }
++            }
++        }
++
++
++        public boolean isEmpty() {
++            if (fast) {
++                return get(map).isEmpty();
++            } else {
++                synchronized (map) {
++                    return get(map).isEmpty();
++                }
++            }
++        }
++
++        public boolean contains(Object o) {
++            if (fast) {
++                return get(map).contains(o);
++            } else {
++                synchronized (map) {
++                    return get(map).contains(o);
++                }
++            }
++        }
++
++        public boolean containsAll(Collection<?> o) {
++            if (fast) {
++                return get(map).containsAll(o);
++            } else {
++                synchronized (map) {
++                    return get(map).containsAll(o);
++                }
++            }
++        }
++
++        public <T> T[] toArray(T[] o) {
++            if (fast) {
++                return get(map).toArray(o);
++            } else {
++                synchronized (map) {
++                    return get(map).toArray(o);
++                }
++            }
++        }
++
++        public Object[] toArray() {
++            if (fast) {
++                return get(map).toArray();
++            } else {
++                synchronized (map) {
++                    return get(map).toArray();
++                }
++            }
++        }
++
++
++        public boolean equals(Object o) {
++            if (o == this) return true;
++            if (fast) {
++                return get(map).equals(o);
++            } else {
++                synchronized (map) {
++                    return get(map).equals(o);
++                }
++            }
++        }
++
++        public int hashCode() {
++            if (fast) {
++                return get(map).hashCode();
++            } else {
++                synchronized (map) {
++                    return get(map).hashCode();
++                }
++            }
++        }
++
++        public boolean add(E o) {
++            throw new UnsupportedOperationException();
++        }
++
++        public boolean addAll(Collection<? extends E> c) {
++            throw new UnsupportedOperationException();
++        }
++
++        public Iterator<E> iterator() {
++            return new CollectionViewIterator();
++        }
++
++        private class CollectionViewIterator implements Iterator<E> {
++
++            private Map expected;
++            private Map.Entry lastReturned = null;
++            private Iterator iterator;
++
++            public CollectionViewIterator() {
++                this.expected = map;
++                this.iterator = expected.entrySet().iterator();
++            }
++
++            public boolean hasNext() {
++                if (expected != map) {
++                    throw new ConcurrentModificationException();
++                }
++                return iterator.hasNext();
++            }
++
++            public E next() {
++                if (expected != map) {
++                    throw new ConcurrentModificationException();
++                }
++                lastReturned = (Map.Entry) iterator.next();
++                return iteratorNext(lastReturned);
++            }
++
++            public void remove() {
++                if (lastReturned == null) {
++                    throw new IllegalStateException();
++                }
++                if (fast) {
++                    synchronized (FastHashMap.this) {
++                        if (expected != map) {
++                            throw new ConcurrentModificationException();
++                        }
++                        FastHashMap.this.remove(lastReturned.getKey());
++                        lastReturned = null;
++                        expected = map;
++                    }
++                } else {
++                    iterator.remove();
++                    lastReturned = null;
++                }
++            }
++        }
++    }
++
++    /**
++     * Set implementation over the keys of the FastHashMap
++     */
++    private class KeySet extends CollectionView<K> implements Set<K> {
++
++        protected Collection get(Map<K, V> map) {
++            return map.keySet();
++        }
++
++        protected K iteratorNext(Map.Entry<K, V> entry) {
++            return entry.getKey();
++        }
++
++
++    }
++
++    /**
++     * Collection implementation over the values of the FastHashMap
++     */
++    private class Values extends CollectionView<V> {
++
++        protected Collection get(Map<K, V> map) {
++            return map.values();
++        }
++
++        protected V iteratorNext(Map.Entry<K, V> entry) {
++            return entry.getValue();
++        }
++    }
++
++    /**
++     * Set implementation over the entries of the FastHashMap
++     */
++    private class EntrySet extends CollectionView<Map.Entry<K, V>> implements Set<Map.Entry<K, V>> {
++
++        protected Collection get(Map<K, V> map) {
++            return map.entrySet();
++        }
++
++        protected Map.Entry<K, V> iteratorNext(Map.Entry<K, V> entry) {
++            return entry;
++        }
++
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/FastTreeMap.java
+@@ -0,0 +1,817 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import java.util.*;
++
++/**
++ * <p>A customized implementation of <code>java.util.TreeMap</code> designed
++ * to operate in a multithreaded environment where the large majority of
++ * method calls are read-only, instead of structural changes.  When operating
++ * in "fast" mode, read calls are non-synchronized and write calls perform the
++ * following steps:</p>
++ * <ul>
++ * <li>Clone the existing collection
++ * <li>Perform the modification on the clone
++ * <li>Replace the existing collection with the (modified) clone
++ * </ul>
++ * <p>When first created, objects of this class default to "slow" mode, where
++ * all accesses of any type are synchronized but no cloning takes place.  This
++ * is appropriate for initially populating the collection, followed by a switch
++ * to "fast" mode (by calling <code>setFast(true)</code>) after initialization
++ * is complete.</p>
++ * <p/>
++ * <p><strong>NOTE</strong>: If you are creating and accessing a
++ * <code>TreeMap</code> only within a single thread, you should use
++ * <code>java.util.TreeMap</code> directly (with no synchronization), for
++ * maximum performance.</p>
++ * <p/>
++ * <p><strong>NOTE</strong>: <i>This class is not cross-platform.
++ * Using it may cause unexpected failures on some architectures.</i>
++ * It suffers from the same problems as the double-checked locking idiom.
++ * In particular, the instruction that clones the internal collection and the
++ * instruction that sets the internal reference to the clone can be executed
++ * or perceived out-of-order.  This means that any read operation might fail
++ * unexpectedly, as it may be reading the state of the internal collection
++ * before the internal collection is fully formed.
++ * For more information on the double-checked locking idiom, see the
++ * <a href="http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html">
++ * Double-Checked Locking Idiom Is Broken Declaration</a>.</p>
++ *
++ * @author Craig R. McClanahan
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 1.0
++ */
++public class FastTreeMap <K,V> extends TreeMap<K, V> {
++
++    /**
++     * The underlying map we are managing.
++     */
++    protected TreeMap<K, V> map = null;
++
++    /**
++     * Are we operating in "fast" mode?
++     */
++    protected boolean fast = false;
++
++
++    // Constructors
++    // ----------------------------------------------------------------------
++
++    /**
++     * Construct a an empty map.
++     */
++    public FastTreeMap() {
++        super();
++        this.map = new TreeMap<K, V>();
++    }
++
++    /**
++     * Construct an empty map with the specified comparator.
++     *
++     * @param comparator the comparator to use for ordering tree elements
++     */
++    public FastTreeMap(Comparator<K> comparator) {
++        super();
++        this.map = new TreeMap<K, V>(comparator);
++    }
++
++    /**
++     * Construct a new map with the same mappings as the specified map,
++     * sorted according to the keys's natural order
++     *
++     * @param map the map whose mappings are to be copied
++     */
++    public FastTreeMap(Map<K, V> map) {
++        super();
++        this.map = new TreeMap<K, V>(map);
++    }
++
++    /**
++     * Construct a new map with the same mappings as the specified map,
++     * sorted according to the same ordering
++     *
++     * @param map the map whose mappings are to be copied
++     */
++    public FastTreeMap(SortedMap<K, V> map) {
++        super();
++        this.map = new TreeMap<K, V>(map);
++    }
++
++
++    // Property access
++    // ----------------------------------------------------------------------
++
++    /**
++     * Returns true if this map is operating in fast mode.
++     *
++     * @return true if this map is operating in fast mode
++     */
++    public boolean getFast() {
++        return (this.fast);
++    }
++
++    /**
++     * Sets whether this map is operating in fast mode.
++     *
++     * @param fast true if this map should operate in fast mode
++     */
++    public void setFast(boolean fast) {
++        this.fast = fast;
++    }
++
++
++    // Map access
++    // ----------------------------------------------------------------------
++    // These methods can forward straight to the wrapped Map in 'fast' mode.
++    // (because they are query methods)
++
++    /**
++     * Return the value to which this map maps the specified key.  Returns
++     * <code>null</code> if the map contains no mapping for this key, or if
++     * there is a mapping with a value of <code>null</code>.  Use the
++     * <code>containsKey()</code> method to disambiguate these cases.
++     *
++     * @param key the key whose value is to be returned
++     * @return the value mapped to that key, or null
++     */
++    public V get(Object key) {
++        if (fast) {
++            return (map.get(key));
++        } else {
++            synchronized (map) {
++                return (map.get(key));
++            }
++        }
++    }
++
++    /**
++     * Return the number of key-value mappings in this map.
++     *
++     * @return the current size of the map
++     */
++    public int size() {
++        if (fast) {
++            return (map.size());
++        } else {
++            synchronized (map) {
++                return (map.size());
++            }
++        }
++    }
++
++    /**
++     * Return <code>true</code> if this map contains no mappings.
++     *
++     * @return is the map currently empty
++     */
++    public boolean isEmpty() {
++        if (fast) {
++            return (map.isEmpty());
++        } else {
++            synchronized (map) {
++                return (map.isEmpty());
++            }
++        }
++    }
++
++    /**
++     * Return <code>true</code> if this map contains a mapping for the
++     * specified key.
++     *
++     * @param key the key to be searched for
++     * @return true if the map contains the key
++     */
++    public boolean containsKey(Object key) {
++        if (fast) {
++            return (map.containsKey(key));
++        } else {
++            synchronized (map) {
++                return (map.containsKey(key));
++            }
++        }
++    }
++
++    /**
++     * Return <code>true</code> if this map contains one or more keys mapping
++     * to the specified value.
++     *
++     * @param value the value to be searched for
++     * @return true if the map contains the value
++     */
++    public boolean containsValue(Object value) {
++        if (fast) {
++            return (map.containsValue(value));
++        } else {
++            synchronized (map) {
++                return (map.containsValue(value));
++            }
++        }
++    }
++
++    /**
++     * Return the comparator used to order this map, or <code>null</code>
++     * if this map uses its keys' natural order.
++     *
++     * @return the comparator used to order the map, or null if natural order
++     */
++    public Comparator<? super K> comparator() {
++        if (fast) {
++            return (map.comparator());
++        } else {
++            synchronized (map) {
++                return (map.comparator());
++            }
++        }
++    }
++
++    /**
++     * Return the first (lowest) key currently in this sorted map.
++     *
++     * @return the first key in the map
++     */
++    public K firstKey() {
++        if (fast) {
++            return (map.firstKey());
++        } else {
++            synchronized (map) {
++                return (map.firstKey());
++            }
++        }
++    }
++
++    /**
++     * Return the last (highest) key currently in this sorted map.
++     *
++     * @return the last key in the map
++     */
++    public K lastKey() {
++        if (fast) {
++            return (map.lastKey());
++        } else {
++            synchronized (map) {
++                return (map.lastKey());
++            }
++        }
++    }
++
++
++    // Map modification
++    // ----------------------------------------------------------------------
++    // These methods perform special behaviour in 'fast' mode.
++    // The map is cloned, updated and then assigned back.
++    // See the comments at the top as to why this won't always work.
++
++    /**
++     * Associate the specified value with the specified key in this map.
++     * If the map previously contained a mapping for this key, the old
++     * value is replaced and returned.
++     *
++     * @param key   the key with which the value is to be associated
++     * @param value the value to be associated with this key
++     * @return the value previously mapped to the key, or null
++     */
++    public V put(K key, V value) {
++        if (fast) {
++            synchronized (this) {
++                TreeMap<K, V> temp = (TreeMap<K, V>) map.clone();
++                V result = temp.put(key, value);
++                map = temp;
++                return (result);
++            }
++        } else {
++            synchronized (map) {
++                return (map.put(key, value));
++            }
++        }
++    }
++
++    /**
++     * Copy all of the mappings from the specified map to this one, replacing
++     * any mappings with the same keys.
++     *
++     * @param in the map whose mappings are to be copied
++     */
++    public void putAll(Map<? extends K, ? extends V> in) {
++        if (fast) {
++            synchronized (this) {
++                TreeMap<K, V> temp = (TreeMap<K, V>) map.clone();
++                temp.putAll(in);
++                map = temp;
++            }
++        } else {
++            synchronized (map) {
++                map.putAll(in);
++            }
++        }
++    }
++
++    /**
++     * Remove any mapping for this key, and return any previously
++     * mapped value.
++     *
++     * @param key the key whose mapping is to be removed
++     * @return the value removed, or null
++     */
++    public V remove(Object key) {
++        if (fast) {
++            synchronized (this) {
++                TreeMap<K, V> temp = (TreeMap<K, V>) map.clone();
++                V result = temp.remove(key);
++                map = temp;
++                return (result);
++            }
++        } else {
++            synchronized (map) {
++                return (map.remove(key));
++            }
++        }
++    }
++
++    /**
++     * Remove all mappings from this map.
++     */
++    public void clear() {
++        if (fast) {
++            synchronized (this) {
++                map = new TreeMap<K, V>();
++            }
++        } else {
++            synchronized (map) {
++                map.clear();
++            }
++        }
++    }
++    
++    
++    // Basic object methods
++    // ----------------------------------------------------------------------
++    
++    /**
++     * Compare the specified object with this list for equality.  This
++     * implementation uses exactly the code that is used to define the
++     * list equals function in the documentation for the
++     * <code>Map.equals</code> method.
++     *
++     * @param o the object to be compared to this list
++     * @return true if the two maps are equal
++     */
++    public boolean equals(Object o) {
++        // Simple tests that require no synchronization
++        if (o == this) {
++            return (true);
++        } else if (!(o instanceof Map)) {
++            return (false);
++        }
++        Map mo = (Map) o;
++
++        // Compare the two maps for equality
++        if (fast) {
++            if (mo.size() != map.size()) {
++                return (false);
++            }
++            Iterator i = map.entrySet().iterator();
++            while (i.hasNext()) {
++                Map.Entry e = (Map.Entry) i.next();
++                Object key = e.getKey();
++                Object value = e.getValue();
++                if (value == null) {
++                    if (!(mo.get(key) == null && mo.containsKey(key))) {
++                        return (false);
++                    }
++                } else {
++                    if (!value.equals(mo.get(key))) {
++                        return (false);
++                    }
++                }
++            }
++            return (true);
++        } else {
++            synchronized (map) {
++                if (mo.size() != map.size()) {
++                    return (false);
++                }
++                Iterator i = map.entrySet().iterator();
++                while (i.hasNext()) {
++                    Map.Entry e = (Map.Entry) i.next();
++                    Object key = e.getKey();
++                    Object value = e.getValue();
++                    if (value == null) {
++                        if (!(mo.get(key) == null && mo.containsKey(key))) {
++                            return (false);
++                        }
++                    } else {
++                        if (!value.equals(mo.get(key))) {
++                            return (false);
++                        }
++                    }
++                }
++                return (true);
++            }
++        }
++    }
++
++    /**
++     * Return the hash code value for this map.  This implementation uses
++     * exactly the code that is used to define the list hash function in the
++     * documentation for the <code>Map.hashCode</code> method.
++     *
++     * @return a suitable integer hash code
++     */
++    public int hashCode() {
++        if (fast) {
++            int h = 0;
++            Iterator i = map.entrySet().iterator();
++            while (i.hasNext()) {
++                h += i.next().hashCode();
++            }
++            return (h);
++        } else {
++            synchronized (map) {
++                int h = 0;
++                Iterator i = map.entrySet().iterator();
++                while (i.hasNext()) {
++                    h += i.next().hashCode();
++                }
++                return (h);
++            }
++        }
++    }
++
++    /**
++     * Return a shallow copy of this <code>FastTreeMap</code> instance.
++     * The keys and values themselves are not copied.
++     *
++     * @return a clone of this map
++     */
++    public FastTreeMap<K, V> clone() {
++        FastTreeMap results = null;
++        if (fast) {
++            results = new FastTreeMap(map);
++        } else {
++            synchronized (map) {
++                results = new FastTreeMap(map);
++            }
++        }
++        results.setFast(getFast());
++        return (results);
++    }
++
++
++    // Sub map views
++    // ----------------------------------------------------------------------
++    
++    /**
++     * Return a view of the portion of this map whose keys are strictly
++     * less than the specified key.
++     *
++     * @param key Key higher than any in the returned map
++     * @return a head map
++     */
++    public SortedMap<K, V> headMap(K key) {
++        if (fast) {
++            return (map.headMap(key));
++        } else {
++            synchronized (map) {
++                return (map.headMap(key));
++            }
++        }
++    }
++
++    /**
++     * Return a view of the portion of this map whose keys are in the
++     * range fromKey (inclusive) to toKey (exclusive).
++     *
++     * @param fromKey Lower limit of keys for the returned map
++     * @param toKey   Upper limit of keys for the returned map
++     * @return a sub map
++     */
++    public SortedMap<K, V> subMap(K fromKey, K toKey) {
++        if (fast) {
++            return (map.subMap(fromKey, toKey));
++        } else {
++            synchronized (map) {
++                return (map.subMap(fromKey, toKey));
++            }
++        }
++    }
++
++    /**
++     * Return a view of the portion of this map whose keys are greater than
++     * or equal to the specified key.
++     *
++     * @param key Key less than or equal to any in the returned map
++     * @return a tail map
++     */
++    public SortedMap<K, V> tailMap(K key) {
++        if (fast) {
++            return (map.tailMap(key));
++        } else {
++            synchronized (map) {
++                return (map.tailMap(key));
++            }
++        }
++    }
++
++
++    // Map views
++    // ----------------------------------------------------------------------
++    
++    /**
++     * Return a collection view of the mappings contained in this map.  Each
++     * element in the returned collection is a <code>Map.Entry</code>.
++     */
++    public Set<Map.Entry<K, V>> entrySet() {
++        return new EntrySet();
++    }
++
++    /**
++     * Return a set view of the keys contained in this map.
++     */
++    public Set<K> keySet() {
++        return new KeySet();
++    }
++
++    /**
++     * Return a collection view of the values contained in this map.
++     */
++    public Collection<V> values() {
++        return new Values();
++    }
++
++    // Map view inner classes
++    // ----------------------------------------------------------------------
++
++    /**
++     * Abstract collection implementation shared by keySet(), values() and entrySet().
++     */
++    private abstract class CollectionView <E> implements Collection<E> {
++
++        public CollectionView() {
++        }
++
++        protected abstract Collection<E> get(Map<K, V> map);
++
++        protected abstract E iteratorNext(Map.Entry<K, V> entry);
++
++
++        public void clear() {
++            if (fast) {
++                synchronized (FastTreeMap.this) {
++                    map = new TreeMap<K, V>();
++                }
++            } else {
++                synchronized (map) {
++                    get(map).clear();
++                }
++            }
++        }
++
++        public boolean remove(Object o) {
++            if (fast) {
++                synchronized (FastTreeMap.this) {
++                    TreeMap<K, V> temp = (TreeMap<K, V>) map.clone();
++                    boolean r = get(temp).remove(o);
++                    map = temp;
++                    return r;
++                }
++            } else {
++                synchronized (map) {
++                    return get(map).remove(o);
++                }
++            }
++        }
++
++        public boolean removeAll(Collection<?> o) {
++            if (fast) {
++                synchronized (FastTreeMap.this) {
++                    TreeMap temp = (TreeMap) map.clone();
++                    boolean r = get(temp).removeAll(o);
++                    map = temp;
++                    return r;
++                }
++            } else {
++                synchronized (map) {
++                    return get(map).removeAll(o);
++                }
++            }
++        }
++
++        public boolean retainAll(Collection<?> o) {
++            if (fast) {
++                synchronized (FastTreeMap.this) {
++                    TreeMap temp = (TreeMap) map.clone();
++                    boolean r = get(temp).retainAll(o);
++                    map = temp;
++                    return r;
++                }
++            } else {
++                synchronized (map) {
++                    return get(map).retainAll(o);
++                }
++            }
++        }
++
++        public int size() {
++            if (fast) {
++                return get(map).size();
++            } else {
++                synchronized (map) {
++                    return get(map).size();
++                }
++            }
++        }
++
++
++        public boolean isEmpty() {
++            if (fast) {
++                return get(map).isEmpty();
++            } else {
++                synchronized (map) {
++                    return get(map).isEmpty();
++                }
++            }
++        }
++
++        public boolean contains(Object o) {
++            if (fast) {
++                return get(map).contains(o);
++            } else {
++                synchronized (map) {
++                    return get(map).contains(o);
++                }
++            }
++        }
++
++        public boolean containsAll(Collection<?> o) {
++            if (fast) {
++                return get(map).containsAll(o);
++            } else {
++                synchronized (map) {
++                    return get(map).containsAll(o);
++                }
++            }
++        }
++
++        public <T> T[] toArray(T[] o) {
++            if (fast) {
++                return get(map).toArray(o);
++            } else {
++                synchronized (map) {
++                    return get(map).toArray(o);
++                }
++            }
++        }
++
++        public Object[] toArray() {
++            if (fast) {
++                return get(map).toArray();
++            } else {
++                synchronized (map) {
++                    return get(map).toArray();
++                }
++            }
++        }
++
++
++        public boolean equals(Object o) {
++            if (o == this) return true;
++            if (fast) {
++                return get(map).equals(o);
++            } else {
++                synchronized (map) {
++                    return get(map).equals(o);
++                }
++            }
++        }
++
++        public int hashCode() {
++            if (fast) {
++                return get(map).hashCode();
++            } else {
++                synchronized (map) {
++                    return get(map).hashCode();
++                }
++            }
++        }
++
++        public boolean add(E o) {
++            throw new UnsupportedOperationException();
++        }
++
++        public boolean addAll(Collection<? extends E> c) {
++            throw new UnsupportedOperationException();
++        }
++
++        public Iterator<E> iterator() {
++            return new CollectionViewIterator();
++        }
++
++        private class CollectionViewIterator implements Iterator<E> {
++
++            private Map<K, V> expected;
++            private Map.Entry<K, V> lastReturned = null;
++            private Iterator<Map.Entry<K, V>> iterator;
++
++            public CollectionViewIterator() {
++                this.expected = map;
++                this.iterator = expected.entrySet().iterator();
++            }
++
++            public boolean hasNext() {
++                if (expected != map) {
++                    throw new ConcurrentModificationException();
++                }
++                return iterator.hasNext();
++            }
++
++            public E next() {
++                if (expected != map) {
++                    throw new ConcurrentModificationException();
++                }
++                lastReturned = (Map.Entry<K, V>) iterator.next();
++                return iteratorNext(lastReturned);
++            }
++
++            public void remove() {
++                if (lastReturned == null) {
++                    throw new IllegalStateException();
++                }
++                if (fast) {
++                    synchronized (FastTreeMap.this) {
++                        if (expected != map) {
++                            throw new ConcurrentModificationException();
++                        }
++                        FastTreeMap.this.remove(lastReturned.getKey());
++                        lastReturned = null;
++                        expected = map;
++                    }
++                } else {
++                    iterator.remove();
++                    lastReturned = null;
++                }
++            }
++        }
++    }
++
++    /**
++     * Set implementation over the keys of the FastTreeMap
++     */
++    private class KeySet extends CollectionView<K> implements Set<K> {
++
++        protected Collection<K> get(Map<K, V> map) {
++            return map.keySet();
++        }
++
++        protected K iteratorNext(Map.Entry<K, V> entry) {
++            return entry.getKey();
++        }
++
++    }
++
++    /**
++     * Collection implementation over the values of the FastTreeMap
++     */
++    private class Values extends CollectionView<V> {
++
++        protected Collection<V> get(Map<K, V> map) {
++            return map.values();
++        }
++
++        protected V iteratorNext(Map.Entry<K, V> entry) {
++            return entry.getValue();
++        }
++    }
++
++    /**
++     * Set implementation over the entries of the FastTreeMap
++     */
++    private class EntrySet extends CollectionView<Map.Entry<K, V>> implements Set<Map.Entry<K, V>> {
++
++        protected Collection<Map.Entry<K, V>> get(Map<K, V> map) {
++            return map.entrySet();
++        }
++
++
++        protected Map.Entry<K, V> iteratorNext(Map.Entry<K, V> entry) {
++            return entry;
++        }
++
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/FixedSizeMap.java
+@@ -0,0 +1,155 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.BoundedMap;
++import org.apache.commons.collections15.collection.UnmodifiableCollection;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * Decorates another <code>Map</code> to fix the size, preventing add/remove.
++ * <p/>
++ * Any action that would change the size of the map is disallowed.
++ * The put method is allowed to change the value associated with an existing
++ * key however.
++ * <p/>
++ * If trying to remove or clear the map, an UnsupportedOperationException is
++ * thrown. If trying to put a new mapping into the map, an
++ * IllegalArgumentException is thrown. This is because the put method can
++ * succeed if the mapping's key already exists in the map, so the put method
++ * is not always unsupported.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class FixedSizeMap <K,V> extends AbstractMapDecorator<K, V> implements Map<K, V>, BoundedMap<K, V>, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 7450927208116179316L;
++
++    /**
++     * Factory method to create a fixed size map.
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    public static <K,V> Map<K, V> decorate(Map<K, V> map) {
++        return new FixedSizeMap<K, V>(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    protected FixedSizeMap(Map<K, V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     * @since Commons Collections 3.1
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(map);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     * @since Commons Collections 3.1
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        map = (Map<K, V>) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    public V put(K key, V value) {
++        if (map.containsKey(key) == false) {
++            throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size");
++        }
++        return map.put(key, value);
++    }
++
++    public void putAll(Map<? extends K, ? extends V> mapToCopy) {
++        for (Iterator it = mapToCopy.keySet().iterator(); it.hasNext();) {
++            if (mapToCopy.containsKey(it.next()) == false) {
++                throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size");
++            }
++        }
++        map.putAll(mapToCopy);
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException("Map is fixed size");
++    }
++
++    public V remove(Object key) {
++        throw new UnsupportedOperationException("Map is fixed size");
++    }
++
++    public Set<Map.Entry<K, V>> entrySet() {
++        Set<Map.Entry<K, V>> set = map.entrySet();
++        // unmodifiable set will still allow modification via Map.Entry objects
++        return UnmodifiableSet.decorate(set);
++    }
++
++    public Set<K> keySet() {
++        Set<K> set = map.keySet();
++        return UnmodifiableSet.decorate(set);
++    }
++
++    public Collection<V> values() {
++        Collection<V> coll = map.values();
++        return UnmodifiableCollection.decorate(coll);
++    }
++
++    public boolean isFull() {
++        return true;
++    }
++
++    public int maxSize() {
++        return size();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/FixedSizeSortedMap.java
+@@ -0,0 +1,167 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.BoundedMap;
++import org.apache.commons.collections15.collection.UnmodifiableCollection;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.*;
++
++/**
++ * Decorates another <code>SortedMap</code> to fix the size blocking add/remove.
++ * <p/>
++ * Any action that would change the size of the map is disallowed.
++ * The put method is allowed to change the value associated with an existing
++ * key however.
++ * <p/>
++ * If trying to remove or clear the map, an UnsupportedOperationException is
++ * thrown. If trying to put a new mapping into the map, an
++ * IllegalArgumentException is thrown. This is because the put method can
++ * succeed if the mapping's key already exists in the map, so the put method
++ * is not always unsupported.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class FixedSizeSortedMap <K,V> extends AbstractSortedMapDecorator<K, V> implements SortedMap<K, V>, BoundedMap<K, V>, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 3126019624511683653L;
++
++    /**
++     * Factory method to create a fixed size sorted map.
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    public static <K,V> SortedMap<K, V> decorate(SortedMap<K, V> map) {
++        return new FixedSizeSortedMap<K, V>(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    protected FixedSizeSortedMap(SortedMap<K, V> map) {
++        super(map);
++    }
++
++    /**
++     * Gets the map being decorated.
++     *
++     * @return the decorated map
++     */
++    protected SortedMap<K, V> getSortedMap() {
++        return (SortedMap<K, V>) map;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(map);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        map = (Map<K, V>) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    public V put(K key, V value) {
++        if (map.containsKey(key) == false) {
++            throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size");
++        }
++        return map.put(key, value);
++    }
++
++    public void putAll(Map<? extends K, ? extends V> mapToCopy) {
++        for (Iterator it = mapToCopy.keySet().iterator(); it.hasNext();) {
++            if (mapToCopy.containsKey(it.next()) == false) {
++                throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size");
++            }
++        }
++        map.putAll(mapToCopy);
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException("Map is fixed size");
++    }
++
++    public V remove(Object key) {
++        throw new UnsupportedOperationException("Map is fixed size");
++    }
++
++    public Set<Map.Entry<K, V>> entrySet() {
++        Set<Map.Entry<K, V>> set = map.entrySet();
++        return UnmodifiableSet.decorate(set);
++    }
++
++    public Set<K> keySet() {
++        Set<K> set = map.keySet();
++        return UnmodifiableSet.decorate(set);
++    }
++
++    public Collection<V> values() {
++        Collection<V> coll = map.values();
++        return UnmodifiableCollection.decorate(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    public SortedMap<K, V> subMap(K fromKey, K toKey) {
++        SortedMap<K, V> map = getSortedMap().subMap(fromKey, toKey);
++        return new FixedSizeSortedMap<K, V>(map);
++    }
++
++    public SortedMap<K, V> headMap(K toKey) {
++        SortedMap<K, V> map = getSortedMap().headMap(toKey);
++        return new FixedSizeSortedMap<K, V>(map);
++    }
++
++    public SortedMap<K, V> tailMap(K fromKey) {
++        SortedMap<K, V> map = getSortedMap().tailMap(fromKey);
++        return new FixedSizeSortedMap<K, V>(map);
++    }
++
++    public boolean isFull() {
++        return true;
++    }
++
++    public int maxSize() {
++        return size();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/Flat3Map.java
+@@ -0,0 +1,1151 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.IterableMap;
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.ResettableIterator;
++import org.apache.commons.collections15.iterators.EmptyIterator;
++import org.apache.commons.collections15.iterators.EmptyMapIterator;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.*;
++
++/**
++ * A <code>Map</code> implementation that stores data in simple fields until
++ * the size is greater than 3.
++ * <p/>
++ * This map is designed for performance and can outstrip HashMap.
++ * It also has good garbage collection characteristics.
++ * <ul>
++ * <li>Optimised for operation at size 3 or less.
++ * <li>Still works well once size 3 exceeded.
++ * <li>Gets at size 3 or less are about 0-10% faster than HashMap,
++ * <li>Puts at size 3 or less are over 4 times faster than HashMap.
++ * <li>Performance 5% slower than HashMap once size 3 exceeded once.
++ * </ul>
++ * The design uses two distinct modes of operation - flat and delegate.
++ * While the map is size 3 or less, operations map straight onto fields using
++ * switch statements. Once size 4 is reached, the map switches to delegate mode
++ * and only switches back when cleared. In delegate mode, all operations are
++ * forwarded straight to a HashMap resulting in the 5% performance loss.
++ * <p/>
++ * The performance gains on puts are due to not needing to create a Map Entry
++ * object. This is a large saving not only in performance but in garbage collection.
++ * <p/>
++ * Whilst in flat mode this map is also easy for the garbage collector to dispatch.
++ * This is because it contains no complex objects or arrays which slow the progress.
++ * <p/>
++ * Do not use <code>Flat3Map</code> if the size is likely to grow beyond 3.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class Flat3Map <K,V> implements IterableMap<K, V>, Serializable, Cloneable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -6701087419741928296L;
++
++    /**
++     * The size of the map, used while in flat mode
++     */
++    private transient int size;
++    /**
++     * Hash, used while in flat mode
++     */
++    private transient int hash1;
++    /**
++     * Hash, used while in flat mode
++     */
++    private transient int hash2;
++    /**
++     * Hash, used while in flat mode
++     */
++    private transient int hash3;
++    /**
++     * Key, used while in flat mode
++     */
++    private transient K key1;
++    /**
++     * Key, used while in flat mode
++     */
++    private transient K key2;
++    /**
++     * Key, used while in flat mode
++     */
++    private transient K key3;
++    /**
++     * Value, used while in flat mode
++     */
++    private transient V value1;
++    /**
++     * Value, used while in flat mode
++     */
++    private transient V value2;
++    /**
++     * Value, used while in flat mode
++     */
++    private transient V value3;
++    /**
++     * Map, used while in delegate mode
++     */
++    private transient AbstractHashedMap<K, V> delegateMap;
++
++    /**
++     * Constructor.
++     */
++    public Flat3Map() {
++        super();
++    }
++
++    /**
++     * Constructor copying elements from another map.
++     *
++     * @param map the map to copy
++     * @throws NullPointerException if the map is null
++     */
++    public Flat3Map(Map<K, V> map) {
++        super();
++        putAll(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the value mapped to the key specified.
++     *
++     * @param key the key
++     * @return the mapped value, null if no match
++     */
++    public V get(Object key) {
++        if (delegateMap != null) {
++            return delegateMap.get(key);
++        }
++        if (key == null) {
++            switch (size) {
++                // drop through
++                case 3:
++                    if (key3 == null) return value3;
++                case 2:
++                    if (key2 == null) return value2;
++                case 1:
++                    if (key1 == null) return value1;
++            }
++        } else {
++            if (size > 0) {
++                int hashCode = key.hashCode();
++                switch (size) {
++                    // drop through
++                    case 3:
++                        if (hash3 == hashCode && key.equals(key3)) return value3;
++                    case 2:
++                        if (hash2 == hashCode && key.equals(key2)) return value2;
++                    case 1:
++                        if (hash1 == hashCode && key.equals(key1)) return value1;
++                }
++            }
++        }
++        return null;
++    }
++
++    /**
++     * Gets the size of the map.
++     *
++     * @return the size
++     */
++    public int size() {
++        if (delegateMap != null) {
++            return delegateMap.size();
++        }
++        return size;
++    }
++
++    /**
++     * Checks whether the map is currently empty.
++     *
++     * @return true if the map is currently size zero
++     */
++    public boolean isEmpty() {
++        return (size() == 0);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Checks whether the map contains the specified key.
++     *
++     * @param key the key to search for
++     * @return true if the map contains the key
++     */
++    public boolean containsKey(Object key) {
++        if (delegateMap != null) {
++            return delegateMap.containsKey(key);
++        }
++        if (key == null) {
++            switch (size) {  // drop through
++                case 3:
++                    if (key3 == null) return true;
++                case 2:
++                    if (key2 == null) return true;
++                case 1:
++                    if (key1 == null) return true;
++            }
++        } else {
++            if (size > 0) {
++                int hashCode = key.hashCode();
++                switch (size) {  // drop through
++                    case 3:
++                        if (hash3 == hashCode && key.equals(key3)) return true;
++                    case 2:
++                        if (hash2 == hashCode && key.equals(key2)) return true;
++                    case 1:
++                        if (hash1 == hashCode && key.equals(key1)) return true;
++                }
++            }
++        }
++        return false;
++    }
++
++    /**
++     * Checks whether the map contains the specified value.
++     *
++     * @param value the value to search for
++     * @return true if the map contains the key
++     */
++    public boolean containsValue(Object value) {
++        if (delegateMap != null) {
++            return delegateMap.containsValue(value);
++        }
++        if (value == null) {  // drop through
++            switch (size) {
++                case 3:
++                    if (value3 == null) return true;
++                case 2:
++                    if (value2 == null) return true;
++                case 1:
++                    if (value1 == null) return true;
++            }
++        } else {
++            switch (size) {  // drop through
++                case 3:
++                    if (value.equals(value3)) return true;
++                case 2:
++                    if (value.equals(value2)) return true;
++                case 1:
++                    if (value.equals(value1)) return true;
++            }
++        }
++        return false;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Puts a key-value mapping into this map.
++     *
++     * @param key   the key to add
++     * @param value the value to add
++     * @return the value previously mapped to this key, null if none
++     */
++    public V put(K key, V value) {
++        if (delegateMap != null) {
++            return delegateMap.put(key, value);
++        }
++        // change existing mapping
++        if (key == null) {
++            switch (size) {  // drop through
++                case 3:
++                    if (key3 == null) {
++                        V old = value3;
++                        value3 = value;
++                        return old;
++                    }
++                case 2:
++                    if (key2 == null) {
++                        V old = value2;
++                        value2 = value;
++                        return old;
++                    }
++                case 1:
++                    if (key1 == null) {
++                        V old = value1;
++                        value1 = value;
++                        return old;
++                    }
++            }
++        } else {
++            if (size > 0) {
++                int hashCode = key.hashCode();
++                switch (size) {  // drop through
++                    case 3:
++                        if (hash3 == hashCode && key.equals(key3)) {
++                            V old = value3;
++                            value3 = value;
++                            return old;
++                        }
++                    case 2:
++                        if (hash2 == hashCode && key.equals(key2)) {
++                            V old = value2;
++                            value2 = value;
++                            return old;
++                        }
++                    case 1:
++                        if (hash1 == hashCode && key.equals(key1)) {
++                            V old = value1;
++                            value1 = value;
++                            return old;
++                        }
++                }
++            }
++        }
++        
++        // add new mapping
++        switch (size) {
++            default:
++                convertToMap();
++                delegateMap.put(key, value);
++                return null;
++            case 2:
++                hash3 = (key == null ? 0 : key.hashCode());
++                key3 = key;
++                value3 = value;
++                break;
++            case 1:
++                hash2 = (key == null ? 0 : key.hashCode());
++                key2 = key;
++                value2 = value;
++                break;
++            case 0:
++                hash1 = (key == null ? 0 : key.hashCode());
++                key1 = key;
++                value1 = value;
++                break;
++        }
++        size++;
++        return null;
++    }
++
++    /**
++     * Puts all the values from the specified map into this map.
++     *
++     * @param map the map to add
++     * @throws NullPointerException if the map is null
++     */
++    public void putAll(Map<? extends K, ? extends V> map) {
++        int size = map.size();
++        if (size == 0) {
++            return;
++        }
++        if (delegateMap != null) {
++            delegateMap.putAll(map);
++            return;
++        }
++        if (size < 4) {
++            for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
++                Map.Entry<? extends K, ? extends V> entry = (Map.Entry<? extends K, ? extends V>) it.next();
++                put(entry.getKey(), entry.getValue());
++            }
++        } else {
++            convertToMap();
++            delegateMap.putAll(map);
++        }
++    }
++
++    /**
++     * Converts the flat map data to a map.
++     */
++    private void convertToMap() {
++        delegateMap = createDelegateMap();
++        switch (size) {  // drop through
++            case 3:
++                delegateMap.put(key3, value3);
++            case 2:
++                delegateMap.put(key2, value2);
++            case 1:
++                delegateMap.put(key1, value1);
++        }
++
++        size = 0;
++        hash1 = hash2 = hash3 = 0;
++        key1 = key2 = key3 = null;
++        value1 = value2 = value3 = null;
++    }
++
++    /**
++     * Create an instance of the map used for storage when in delegation mode.
++     * <p/>
++     * This can be overridden by subclasses to provide a different map implementation.
++     * Not every AbstractHashedMap is suitable, identity and reference based maps
++     * would be poor choices.
++     *
++     * @return a new AbstractHashedMap or subclass
++     * @since Commons Collections 3.1
++     */
++    protected AbstractHashedMap<K, V> createDelegateMap() {
++        return new HashedMap<K, V>();
++    }
++
++    /**
++     * Removes the specified mapping from this map.
++     *
++     * @param key the mapping to remove
++     * @return the value mapped to the removed key, null if key not in map
++     */
++    public V remove(Object key) {
++        if (delegateMap != null) {
++            return delegateMap.remove(key);
++        }
++        if (size == 0) {
++            return null;
++        }
++        if (key == null) {
++            switch (size) {  // drop through
++                case 3:
++                    if (key3 == null) {
++                        V old = value3;
++                        hash3 = 0;
++                        key3 = null;
++                        value3 = null;
++                        size = 2;
++                        return old;
++                    }
++                    if (key2 == null) {
++                        V old = value3;
++                        hash2 = hash3;
++                        key2 = key3;
++                        value2 = value3;
++                        hash3 = 0;
++                        key3 = null;
++                        value3 = null;
++                        size = 2;
++                        return old;
++                    }
++                    if (key1 == null) {
++                        V old = value3;
++                        hash1 = hash3;
++                        key1 = key3;
++                        value1 = value3;
++                        hash3 = 0;
++                        key3 = null;
++                        value3 = null;
++                        size = 2;
++                        return old;
++                    }
++                    return null;
++                case 2:
++                    if (key2 == null) {
++                        V old = value2;
++                        hash2 = 0;
++                        key2 = null;
++                        value2 = null;
++                        size = 1;
++                        return old;
++                    }
++                    if (key1 == null) {
++                        V old = value2;
++                        hash1 = hash2;
++                        key1 = key2;
++                        value1 = value2;
++                        hash2 = 0;
++                        key2 = null;
++                        value2 = null;
++                        size = 1;
++                        return old;
++                    }
++                    return null;
++                case 1:
++                    if (key1 == null) {
++                        V old = value1;
++                        hash1 = 0;
++                        key1 = null;
++                        value1 = null;
++                        size = 0;
++                        return old;
++                    }
++            }
++        } else {
++            if (size > 0) {
++                int hashCode = key.hashCode();
++                switch (size) {  // drop through
++                    case 3:
++                        if (hash3 == hashCode && key.equals(key3)) {
++                            V old = value3;
++                            hash3 = 0;
++                            key3 = null;
++                            value3 = null;
++                            size = 2;
++                            return old;
++                        }
++                        if (hash2 == hashCode && key.equals(key2)) {
++                            V old = value3;
++                            hash2 = hash3;
++                            key2 = key3;
++                            value2 = value3;
++                            hash3 = 0;
++                            key3 = null;
++                            value3 = null;
++                            size = 2;
++                            return old;
++                        }
++                        if (hash1 == hashCode && key.equals(key1)) {
++                            V old = value3;
++                            hash1 = hash3;
++                            key1 = key3;
++                            value1 = value3;
++                            hash3 = 0;
++                            key3 = null;
++                            value3 = null;
++                            size = 2;
++                            return old;
++                        }
++                        return null;
++                    case 2:
++                        if (hash2 == hashCode && key.equals(key2)) {
++                            V old = value2;
++                            hash2 = 0;
++                            key2 = null;
++                            value2 = null;
++                            size = 1;
++                            return old;
++                        }
++                        if (hash1 == hashCode && key.equals(key1)) {
++                            V old = value2;
++                            hash1 = hash2;
++                            key1 = key2;
++                            value1 = value2;
++                            hash2 = 0;
++                            key2 = null;
++                            value2 = null;
++                            size = 1;
++                            return old;
++                        }
++                        return null;
++                    case 1:
++                        if (hash1 == hashCode && key.equals(key1)) {
++                            V old = value1;
++                            hash1 = 0;
++                            key1 = null;
++                            value1 = null;
++                            size = 0;
++                            return old;
++                        }
++                }
++            }
++        }
++        return null;
++    }
++
++    /**
++     * Clears the map, resetting the size to zero and nullifying references
++     * to avoid garbage collection issues.
++     */
++    public void clear() {
++        if (delegateMap != null) {
++            delegateMap.clear();  // should aid gc
++            delegateMap = null;  // switch back to flat mode
++        } else {
++            size = 0;
++            hash1 = hash2 = hash3 = 0;
++            key1 = key2 = key3 = null;
++            value1 = value2 = value3 = null;
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an iterator over the map.
++     * Changes made to the iterator affect this map.
++     * <p/>
++     * A MapIterator returns the keys in the map. It also provides convenient
++     * methods to get the key and value, and set the value.
++     * It avoids the need to create an entrySet/keySet/values object.
++     * It also avoids creating the Map Entry object.
++     *
++     * @return the map iterator
++     */
++    public MapIterator<K, V> mapIterator() {
++        if (delegateMap != null) {
++            return delegateMap.mapIterator();
++        }
++        if (size == 0) {
++            return EmptyMapIterator.INSTANCE;
++        }
++        return new FlatMapIterator<K, V>(this);
++    }
++
++    /**
++     * FlatMapIterator
++     */
++    static class FlatMapIterator <K,V> implements MapIterator<K, V>, ResettableIterator<K> {
++        private final Flat3Map<K, V> parent;
++        private int nextIndex = 0;
++        private boolean canRemove = false;
++
++        FlatMapIterator(Flat3Map<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public boolean hasNext() {
++            return (nextIndex < parent.size);
++        }
++
++        public K next() {
++            if (hasNext() == false) {
++                throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
++            }
++            canRemove = true;
++            nextIndex++;
++            return getKey();
++        }
++
++        public void remove() {
++            if (canRemove == false) {
++                throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
++            }
++            parent.remove(getKey());
++            nextIndex--;
++            canRemove = false;
++        }
++
++        public K getKey() {
++            if (canRemove == false) {
++                throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
++            }
++            switch (nextIndex) {
++                case 3:
++                    return parent.key3;
++                case 2:
++                    return parent.key2;
++                case 1:
++                    return parent.key1;
++            }
++            throw new IllegalStateException("Invalid map index");
++        }
++
++        public V getValue() {
++            if (canRemove == false) {
++                throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
++            }
++            switch (nextIndex) {
++                case 3:
++                    return parent.value3;
++                case 2:
++                    return parent.value2;
++                case 1:
++                    return parent.value1;
++            }
++            throw new IllegalStateException("Invalid map index");
++        }
++
++        public V setValue(V value) {
++            if (canRemove == false) {
++                throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
++            }
++            V old = getValue();
++            switch (nextIndex) {
++                case 3:
++                    parent.value3 = value;
++                case 2:
++                    parent.value2 = value;
++                case 1:
++                    parent.value1 = value;
++            }
++            return old;
++        }
++
++        public void reset() {
++            nextIndex = 0;
++            canRemove = false;
++        }
++
++        public String toString() {
++            if (canRemove) {
++                return "Iterator[" + getKey() + "=" + getValue() + "]";
++            } else {
++                return "Iterator[]";
++            }
++        }
++    }
++
++    /**
++     * Gets the entrySet view of the map.
++     * Changes made to the view affect this map.
++     * The Map Entry is not an independent object and changes as the
++     * iterator progresses.
++     * To simply iterate through the entries, use {@link #mapIterator()}.
++     *
++     * @return the entrySet view
++     */
++    public Set<Map.Entry<K, V>> entrySet() {
++        if (delegateMap != null) {
++            return delegateMap.entrySet();
++        }
++        return new EntrySet<K, V>(this);
++    }
++
++    /**
++     * EntrySet
++     */
++    static class EntrySet <K,V> extends AbstractSet<Map.Entry<K, V>> {
++        private final Flat3Map<K, V> parent;
++
++        EntrySet(Flat3Map<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public int size() {
++            return parent.size();
++        }
++
++        public void clear() {
++            parent.clear();
++        }
++
++        public boolean remove(Object obj) {
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++            Map.Entry entry = (Map.Entry) obj;
++            Object key = entry.getKey();
++            boolean result = parent.containsKey(key);
++            parent.remove(key);
++            return result;
++        }
++
++        public Iterator<Map.Entry<K, V>> iterator() {
++            if (parent.delegateMap != null) {
++                return parent.delegateMap.entrySet().iterator();
++            }
++            if (parent.size() == 0) {
++                return EmptyIterator.INSTANCE;
++            }
++            return new EntrySetIterator<K, V>(parent);
++        }
++    }
++
++    static class EntrySetIterator <K,V> extends IteratorBase<K, V> implements Iterator<Map.Entry<K, V>> {
++
++        public EntrySetIterator(Flat3Map<K, V> flat3Map) {
++            super(flat3Map);
++        }
++
++        public Entry<K, V> next() {
++            return superNext();  //To change body of implemented methods use File | Settings | File Templates.
++        }
++
++    }
++
++    /**
++     * EntrySetIterator and MapEntry
++     */
++    static class IteratorBase <K,V> implements Map.Entry<K, V> {
++        private final Flat3Map<K, V> parent;
++        private int nextIndex = 0;
++        private boolean canRemove = false;
++
++        IteratorBase(Flat3Map<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public boolean hasNext() {
++            return (nextIndex < parent.size);
++        }
++
++        public void remove() {
++            if (canRemove == false) {
++                throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
++            }
++            parent.remove(getKey());
++            nextIndex--;
++            canRemove = false;
++        }
++
++        public K getKey() {
++            if (canRemove == false) {
++                throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
++            }
++            switch (nextIndex) {
++                case 3:
++                    return parent.key3;
++                case 2:
++                    return parent.key2;
++                case 1:
++                    return parent.key1;
++            }
++            throw new IllegalStateException("Invalid map index");
++        }
++
++        public Map.Entry<K, V> superNext() {
++            if (hasNext() == false) {
++                throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
++            }
++            canRemove = true;
++            nextIndex++;
++            return this;
++        }
++
++        public V getValue() {
++            if (canRemove == false) {
++                throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
++            }
++            switch (nextIndex) {
++                case 3:
++                    return parent.value3;
++                case 2:
++                    return parent.value2;
++                case 1:
++                    return parent.value1;
++            }
++            throw new IllegalStateException("Invalid map index");
++        }
++
++        public V setValue(V value) {
++            if (canRemove == false) {
++                throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
++            }
++            V old = getValue();
++            switch (nextIndex) {
++                case 3:
++                    parent.value3 = value;
++                case 2:
++                    parent.value2 = value;
++                case 1:
++                    parent.value1 = value;
++            }
++            return old;
++        }
++
++        public boolean equals(Object obj) {
++            if (canRemove == false) {
++                return false;
++            }
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++            Map.Entry other = (Map.Entry) obj;
++            Object key = getKey();
++            Object value = getValue();
++            return (key == null ? other.getKey() == null : key.equals(other.getKey())) && (value == null ? other.getValue() == null : value.equals(other.getValue()));
++        }
++
++        public int hashCode() {
++            if (canRemove == false) {
++                return 0;
++            }
++            Object key = getKey();
++            Object value = getValue();
++            return (key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode());
++        }
++
++        public String toString() {
++            if (canRemove) {
++                return getKey() + "=" + getValue();
++            } else {
++                return "";
++            }
++        }
++    }
++
++    /**
++     * Gets the keySet view of the map.
++     * Changes made to the view affect this map.
++     * To simply iterate through the keys, use {@link #mapIterator()}.
++     *
++     * @return the keySet view
++     */
++    public Set keySet() {
++        if (delegateMap != null) {
++            return delegateMap.keySet();
++        }
++        return new KeySet(this);
++    }
++
++    /**
++     * KeySet
++     */
++    static class KeySet <K,V> extends AbstractSet<K> {
++        private final Flat3Map<K, V> parent;
++
++        KeySet(Flat3Map<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public int size() {
++            return parent.size();
++        }
++
++        public void clear() {
++            parent.clear();
++        }
++
++        public boolean contains(Object key) {
++            return parent.containsKey(key);
++        }
++
++        public boolean remove(Object key) {
++            boolean result = parent.containsKey(key);
++            parent.remove(key);
++            return result;
++        }
++
++        public Iterator<K> iterator() {
++            if (parent.delegateMap != null) {
++                return parent.delegateMap.keySet().iterator();
++            }
++            if (parent.size() == 0) {
++                return EmptyIterator.INSTANCE;
++            }
++            return new KeySetIterator<K, V>(parent);
++        }
++    }
++
++    /**
++     * KeySetIterator
++     */
++    static class KeySetIterator <K,V> extends IteratorBase<K, V> implements Iterator<K> {
++
++        KeySetIterator(Flat3Map<K, V> parent) {
++            super(parent);
++        }
++
++        public K next() {
++            superNext();
++            return getKey();
++        }
++    }
++
++    /**
++     * Gets the values view of the map.
++     * Changes made to the view affect this map.
++     * To simply iterate through the values, use {@link #mapIterator()}.
++     *
++     * @return the values view
++     */
++    public Collection<V> values() {
++        if (delegateMap != null) {
++            return delegateMap.values();
++        }
++        return new Values<K, V>(this);
++    }
++
++    /**
++     * Values
++     */
++    static class Values <K,V> extends AbstractCollection<V> {
++        private final Flat3Map<K, V> parent;
++
++        Values(Flat3Map<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public int size() {
++            return parent.size();
++        }
++
++        public void clear() {
++            parent.clear();
++        }
++
++        public boolean contains(Object value) {
++            return parent.containsValue(value);
++        }
++
++        public Iterator<V> iterator() {
++            if (parent.delegateMap != null) {
++                return parent.delegateMap.values().iterator();
++            }
++            if (parent.size() == 0) {
++                return EmptyIterator.INSTANCE;
++            }
++            return new ValuesIterator<K, V>(parent);
++        }
++    }
++
++    /**
++     * ValuesIterator
++     */
++    static class ValuesIterator <K,V> extends IteratorBase<K, V> implements Iterator<V> {
++
++        ValuesIterator(Flat3Map<K, V> parent) {
++            super(parent);
++        }
++
++        public V next() {
++            superNext();
++            return getValue();
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeInt(size());
++        for (MapIterator it = mapIterator(); it.hasNext();) {
++            out.writeObject(it.next());  // key
++            out.writeObject(it.getValue());  // value
++        }
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        int count = in.readInt();
++        if (count > 3) {
++            delegateMap = createDelegateMap();
++        }
++        for (int i = count; i > 0; i--) {
++            put((K) in.readObject(), (V) in.readObject());
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Clones the map without cloning the keys or values.
++     *
++     * @return a shallow clone
++     * @since Commons Collections 3.1
++     */
++    public Object clone() {
++        try {
++            Flat3Map cloned = (Flat3Map) super.clone();
++            if (cloned.delegateMap != null) {
++                cloned.delegateMap = (HashedMap) cloned.delegateMap.clone();
++            }
++            return cloned;
++        } catch (CloneNotSupportedException ex) {
++            throw new InternalError();
++        }
++    }
++
++    /**
++     * Compares this map with another.
++     *
++     * @param obj the object to compare to
++     * @return true if equal
++     */
++    public boolean equals(Object obj) {
++        if (obj == this) {
++            return true;
++        }
++        if (delegateMap != null) {
++            return delegateMap.equals(obj);
++        }
++        if (obj instanceof Map == false) {
++            return false;
++        }
++        Map other = (Map) obj;
++        if (size != other.size()) {
++            return false;
++        }
++        if (size > 0) {
++            Object otherValue = null;
++            switch (size) {  // drop through
++                case 3:
++                    if (other.containsKey(key3) == false) {
++                        otherValue = other.get(key3);
++                        if (value3 == null ? otherValue != null : !value3.equals(otherValue)) {
++                            return false;
++                        }
++                    }
++                case 2:
++                    if (other.containsKey(key2) == false) {
++                        otherValue = other.get(key2);
++                        if (value2 == null ? otherValue != null : !value2.equals(otherValue)) {
++                            return false;
++                        }
++                    }
++                case 1:
++                    if (other.containsKey(key1) == false) {
++                        otherValue = other.get(key1);
++                        if (value1 == null ? otherValue != null : !value1.equals(otherValue)) {
++                            return false;
++                        }
++                    }
++            }
++        }
++        return true;
++    }
++
++    /**
++     * Gets the standard Map hashCode.
++     *
++     * @return the hash code defined in the Map interface
++     */
++    public int hashCode() {
++        if (delegateMap != null) {
++            return delegateMap.hashCode();
++        }
++        int total = 0;
++        switch (size) {  // drop through
++            case 3:
++                total += (hash3 ^ (value3 == null ? 0 : value3.hashCode()));
++            case 2:
++                total += (hash2 ^ (value2 == null ? 0 : value2.hashCode()));
++            case 1:
++                total += (hash1 ^ (value1 == null ? 0 : value1.hashCode()));
++        }
++        return total;
++    }
++
++    /**
++     * Gets the map as a String.
++     *
++     * @return a string version of the map
++     */
++    public String toString() {
++        if (delegateMap != null) {
++            return delegateMap.toString();
++        }
++        if (size == 0) {
++            return "{}";
++        }
++        StringBuffer buf = new StringBuffer(128);
++        buf.append('{');
++        switch (size) {  // drop through
++            case 3:
++                buf.append(key3);
++                buf.append('=');
++                buf.append(value3);
++                buf.append(',');
++            case 2:
++                buf.append(key2);
++                buf.append('=');
++                buf.append(value2);
++                buf.append(',');
++            case 1:
++                buf.append(key1);
++                buf.append('=');
++                buf.append(value1);
++        }
++        buf.append('}');
++        return buf.toString();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/HashedMap.java
+@@ -0,0 +1,111 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Map;
++
++/**
++ * A <code>Map</code> implementation that is a general purpose alternative
++ * to <code>HashMap</code>.
++ * <p/>
++ * This implementation improves on the JDK1.4 HashMap by adding the
++ * {@link org.apache.commons.collections15.MapIterator MapIterator}
++ * functionality and many methods for subclassing.
++ * <p/>
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class HashedMap <K,V> extends AbstractHashedMap<K, V> implements Serializable, Cloneable {
++
++    /**
++     * Serialisation version
++     */
++    private static final long serialVersionUID = -1788199231038721040L;
++
++    /**
++     * Constructs a new empty map with default size and load factor.
++     */
++    public HashedMap() {
++        super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity.
++     *
++     * @param initialCapacity the initial capacity
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     */
++    public HashedMap(int initialCapacity) {
++        super(initialCapacity);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity and
++     * load factor.
++     *
++     * @param initialCapacity the initial capacity
++     * @param loadFactor      the load factor
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     * @throws IllegalArgumentException if the load factor is less than zero
++     */
++    public HashedMap(int initialCapacity, float loadFactor) {
++        super(initialCapacity, loadFactor);
++    }
++
++    /**
++     * Constructor copying elements from another map.
++     *
++     * @param map the map to copy
++     * @throws NullPointerException if the map is null
++     */
++    public HashedMap(Map<? extends K, ? extends V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Clones the map without cloning the keys or values.
++     *
++     * @return a shallow clone
++     */
++    public Object clone() {
++        return super.clone();
++    }
++
++    /**
++     * Write the map out using a custom routine.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        doWriteObject(out);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        doReadObject(in);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/IdentityMap.java
+@@ -0,0 +1,186 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Map;
++
++/**
++ * A <code>Map</code> implementation that matches keys and values based
++ * on <code>==</code> not <code>equals()</code>.
++ * <p/>
++ * This map will violate the detail of various Map and map view contracts.
++ * As a general rule, don't compare this map to other maps.
++ *
++ * @author java util HashMap
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class IdentityMap <K,V> extends AbstractHashedMap<K, V> implements Serializable, Cloneable {
++
++    /**
++     * Serialisation version
++     */
++    private static final long serialVersionUID = 2028493495224302329L;
++
++    /**
++     * Constructs a new empty map with default size and load factor.
++     */
++    public IdentityMap() {
++        super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity.
++     *
++     * @param initialCapacity the initial capacity
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     */
++    public IdentityMap(int initialCapacity) {
++        super(initialCapacity);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity and
++     * load factor.
++     *
++     * @param initialCapacity the initial capacity
++     * @param loadFactor      the load factor
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     * @throws IllegalArgumentException if the load factor is less than zero
++     */
++    public IdentityMap(int initialCapacity, float loadFactor) {
++        super(initialCapacity, loadFactor);
++    }
++
++    /**
++     * Constructor copying elements from another map.
++     *
++     * @param map the map to copy
++     * @throws NullPointerException if the map is null
++     */
++    public IdentityMap(Map<? extends K, ? extends V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the hash code for the key specified.
++     * This implementation uses the identity hash code.
++     *
++     * @param key the key to get a hash code for
++     * @return the hash code
++     */
++    protected int hash(Object key) {
++        return System.identityHashCode(key);
++    }
++
++    /**
++     * Compares two keys for equals.
++     * This implementation uses <code>==</code>.
++     *
++     * @param key1 the first key to compare
++     * @param key2 the second key to compare
++     * @return true if equal by identity
++     */
++    protected boolean isEqualKey(Object key1, Object key2) {
++        return (key1 == key2);
++    }
++
++    /**
++     * Compares two values for equals.
++     * This implementation uses <code>==</code>.
++     *
++     * @param value1 the first value to compare
++     * @param value2 the second value to compare
++     * @return true if equal by identity
++     */
++    protected boolean isEqualValue(Object value1, Object value2) {
++        return (value1 == value2);
++    }
++
++    /**
++     * Creates an entry to store the data.
++     * This implementation creates an IdentityEntry instance.
++     *
++     * @param next     the next entry in sequence
++     * @param hashCode the hash code to use
++     * @param key      the key to store
++     * @param value    the value to store
++     * @return the newly created entry
++     */
++    protected HashEntry<K, V> createEntry(HashEntry<K, V> next, int hashCode, K key, V value) {
++        return new IdentityEntry<K, V>(next, hashCode, key, value);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * HashEntry
++     */
++    protected static class IdentityEntry <K,V> extends HashEntry<K, V> {
++
++        protected IdentityEntry(HashEntry<K, V> next, int hashCode, K key, V value) {
++            super(next, hashCode, key, value);
++        }
++
++        public boolean equals(Object obj) {
++            if (obj == this) {
++                return true;
++            }
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++            Map.Entry other = (Map.Entry) obj;
++            return (getKey() == other.getKey()) && (getValue() == other.getValue());
++        }
++
++        public int hashCode() {
++            return System.identityHashCode(getKey()) ^ System.identityHashCode(getValue());
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Clones the map without cloning the keys or values.
++     *
++     * @return a shallow clone
++     */
++    public Object clone() {
++        return super.clone();
++    }
++
++    /**
++     * Write the map out using a custom routine.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        doWriteObject(out);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        doReadObject(in);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/LRUMap.java
+@@ -0,0 +1,398 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.BoundedMap;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Map;
++
++/**
++ * A <code>Map</code> implementation with a fixed maximum size which removes
++ * the least recently used entry if an entry is added when full.
++ * <p/>
++ * The least recently used algorithm works on the get and put operations only.
++ * Iteration of any kind, including setting the value by iteration, does not
++ * change the order. Queries such as containsKey and containsValue or access
++ * via views also do not change the order.
++ * <p/>
++ * The map implements <code>OrderedMap</code> and entries may be queried using
++ * the bidirectional <code>OrderedMapIterator</code>. The order returned is
++ * least recently used to most recently used. Iterators from map views can
++ * also be cast to <code>OrderedIterator</code> if required.
++ * <p/>
++ * All the available iterators can be reset back to the start by casting to
++ * <code>ResettableIterator</code> and calling <code>reset()</code>.
++ *
++ * @author James Strachan
++ * @author Morgan Delagrange
++ * @author Stephen Colebourne
++ * @author Mike Pettypiece
++ * @author Matt Hall, John Watkinson, Mario Ivankovits
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0 (previously in main package v1.0)
++ */
++public class LRUMap <K,V> extends AbstractLinkedMap<K, V> implements BoundedMap<K, V>, Serializable, Cloneable {
++
++    /**
++     * Serialisation version
++     */
++    static final long serialVersionUID = -612114643488955218L;
++    /**
++     * Default maximum size
++     */
++    protected static final int DEFAULT_MAX_SIZE = 100;
++
++    /**
++     * Maximum size
++     */
++    private transient int maxSize;
++    /**
++     * Scan behaviour
++     */
++    private boolean scanUntilRemovable;
++
++    /**
++     * Constructs a new empty map with a maximum size of 100.
++     */
++    public LRUMap() {
++        this(DEFAULT_MAX_SIZE, DEFAULT_LOAD_FACTOR, false);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified maximum size.
++     *
++     * @param maxSize the maximum size of the map
++     * @throws IllegalArgumentException if the maximum size is less than one
++     */
++    public LRUMap(int maxSize) {
++        this(maxSize, DEFAULT_LOAD_FACTOR);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified maximum size.
++     *
++     * @param maxSize            the maximum size of the map
++     * @param scanUntilRemovable scan until a removeable entry is found, default false
++     * @throws IllegalArgumentException if the maximum size is less than one
++     * @since Commons Collections 3.1
++     */
++    public LRUMap(int maxSize, boolean scanUntilRemovable) {
++        this(maxSize, DEFAULT_LOAD_FACTOR, scanUntilRemovable);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity and
++     * load factor.
++     *
++     * @param maxSize    the maximum size of the map, -1 for no limit,
++     * @param loadFactor the load factor
++     * @throws IllegalArgumentException if the maximum size is less than one
++     * @throws IllegalArgumentException if the load factor is less than zero
++     */
++    public LRUMap(int maxSize, float loadFactor) {
++        this(maxSize, loadFactor, false);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity and
++     * load factor.
++     *
++     * @param maxSize            the maximum size of the map, -1 for no limit,
++     * @param loadFactor         the load factor
++     * @param scanUntilRemovable scan until a removeable entry is found, default false
++     * @throws IllegalArgumentException if the maximum size is less than one
++     * @throws IllegalArgumentException if the load factor is less than zero
++     * @since Commons Collections 3.1
++     */
++    public LRUMap(int maxSize, float loadFactor, boolean scanUntilRemovable) {
++        super((maxSize < 1 ? DEFAULT_CAPACITY : maxSize), loadFactor);
++        if (maxSize < 1) {
++            throw new IllegalArgumentException("LRUMap max size must be greater than 0");
++        }
++        this.maxSize = maxSize;
++        this.scanUntilRemovable = scanUntilRemovable;
++    }
++
++    /**
++     * Constructor copying elements from another map.
++     * <p/>
++     * The maximum size is set from the map's size.
++     *
++     * @param map the map to copy
++     * @throws NullPointerException     if the map is null
++     * @throws IllegalArgumentException if the map is empty
++     */
++    public LRUMap(Map<? extends K, ? extends V> map) {
++        this(map, false);
++    }
++
++    /**
++     * Constructor copying elements from another map.
++     * <p/>
++     * The maximum size is set from the map's size.
++     *
++     * @param map                the map to copy
++     * @param scanUntilRemovable scan until a removeable entry is found, default false
++     * @throws NullPointerException     if the map is null
++     * @throws IllegalArgumentException if the map is empty
++     * @since Commons Collections 3.1
++     */
++    public LRUMap(Map<? extends K, ? extends V> map, boolean scanUntilRemovable) {
++        this(map.size(), DEFAULT_LOAD_FACTOR, scanUntilRemovable);
++        putAll(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the value mapped to the key specified.
++     * <p/>
++     * This operation changes the position of the key in the map to the
++     * most recently used position (first).
++     *
++     * @param key the key
++     * @return the mapped value, null if no match
++     */
++    public V get(Object key) {
++        LinkEntry<K, V> entry = (LinkEntry<K, V>) getEntry(key);
++        if (entry == null) {
++            return null;
++        }
++        moveToMRU(entry);
++        return entry.getValue();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Moves an entry to the MRU position at the end of the list.
++     * <p/>
++     * This implementation moves the updated entry to the end of the list.
++     *
++     * @param entry the entry to update
++     */
++    protected void moveToMRU(LinkEntry<K, V> entry) {
++        if (entry.after != header) {
++            modCount++;
++            // remove
++            entry.before.after = entry.after;
++            entry.after.before = entry.before;
++            // add first
++            entry.after = header;
++            entry.before = header.before;
++            header.before.after = entry;
++            header.before = entry;
++        }
++    }
++
++    /**
++     * Updates an existing key-value mapping.
++     * <p/>
++     * This implementation moves the updated entry to the top of the list
++     * using {@link #moveToMRU(org.apache.commons.collections15.map.AbstractLinkedMap.LinkEntry)}.
++     *
++     * @param entry    the entry to update
++     * @param newValue the new value to store
++     */
++    protected void updateEntry(HashEntry<K, V> entry, V newValue) {
++        moveToMRU((LinkEntry<K, V>) entry);  // handles modCount
++        entry.setValue(newValue);
++    }
++
++    /**
++     * Adds a new key-value mapping into this map.
++     * <p/>
++     * This implementation checks the LRU size and determines whether to
++     * discard an entry or not using {@link #removeLRU(org.apache.commons.collections15.map.AbstractLinkedMap.LinkEntry)}.
++     * <p/>
++     * From Commons Collections 3.1 this method uses {@link #isFull()} rather
++     * than accessing <code>size</code> and <code>maxSize</code> directly.
++     * It also handles the scanUntilRemovable functionality.
++     *
++     * @param hashIndex the index into the data array to store at
++     * @param hashCode  the hash code of the key to add
++     * @param key       the key to add
++     * @param value     the value to add
++     */
++    protected void addMapping(int hashIndex, int hashCode, K key, V value) {
++        if (isFull()) {
++            LinkEntry reuse = header.after;
++            boolean removeLRUEntry = false;
++            if (scanUntilRemovable) {
++                while (reuse != header) {
++                    if (removeLRU(reuse)) {
++                        removeLRUEntry = true;
++                        break;
++                    }
++                    reuse = reuse.after;
++                }
++            } else {
++                removeLRUEntry = removeLRU(reuse);
++            }
++
++            if (removeLRUEntry) {
++                reuseMapping(reuse, hashIndex, hashCode, key, value);
++            } else {
++                super.addMapping(hashIndex, hashCode, key, value);
++            }
++        } else {
++            super.addMapping(hashIndex, hashCode, key, value);
++        }
++    }
++
++    /**
++     * Reuses an entry by removing it and moving it to a new place in the map.
++     * <p/>
++     * This method uses {@link #removeEntry}, {@link #reuseEntry} and {@link #addEntry}.
++     *
++     * @param entry     the entry to reuse
++     * @param hashIndex the index into the data array to store at
++     * @param hashCode  the hash code of the key to add
++     * @param key       the key to add
++     * @param value     the value to add
++     */
++    protected void reuseMapping(LinkEntry<K, V> entry, int hashIndex, int hashCode, K key, V value) {
++        // find the entry before the entry specified in the hash table
++        // remember that the parameters (except the first) refer to the new entry,
++        // not the old one
++        int removeIndex = hashIndex(entry.hashCode, data.length);
++        HashEntry<K, V> loop = data[removeIndex];
++        HashEntry<K, V> previous = null;
++        while (loop != entry) {
++            previous = loop;
++            loop = loop.next;
++        }
++        
++        // reuse the entry
++        modCount++;
++        removeEntry(entry, removeIndex, previous);
++        reuseEntry(entry, hashIndex, hashCode, key, value);
++        addEntry(entry, hashIndex);
++    }
++
++    /**
++     * Subclass method to control removal of the least recently used entry from the map.
++     * <p/>
++     * This method exists for subclasses to override. A subclass may wish to
++     * provide cleanup of resources when an entry is removed. For example:
++     * <pre>
++     * protected boolean removeLRU(LinkEntry entry) {
++     *   releaseResources(entry.getValue());  // release resources held by entry
++     *   return true;  // actually delete entry
++     * }
++     * </pre>
++     * <p/>
++     * Alternatively, a subclass may choose to not remove the entry or selectively
++     * keep certain LRU entries. For example:
++     * <pre>
++     * protected boolean removeLRU(LinkEntry entry) {
++     *   if (entry.getKey().toString().startsWith("System.")) {
++     *     return false;  // entry not removed from LRUMap
++     *   } else {
++     *     return true;  // actually delete entry
++     *   }
++     * }
++     * </pre>
++     * The effect of returning false is dependent on the scanUntilRemovable flag.
++     * If the flag is true, the next LRU entry will be passed to this method and so on
++     * until one returns false and is removed, or every entry in the map has been passed.
++     * If the scanUntilRemovable flag is false, the map will exceed the maximum size.
++     * <p/>
++     * NOTE: Commons Collections 3.0 passed the wrong entry to this method.
++     * This is fixed in version 3.1 onwards.
++     *
++     * @param entry the entry to be removed
++     */
++    protected boolean removeLRU(LinkEntry<K, V> entry) {
++        return true;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Returns true if this map is full and no new mappings can be added.
++     *
++     * @return <code>true</code> if the map is full
++     */
++    public boolean isFull() {
++        return (size >= maxSize);
++    }
++
++    /**
++     * Gets the maximum size of the map (the bound).
++     *
++     * @return the maximum number of elements the map can hold
++     */
++    public int maxSize() {
++        return maxSize;
++    }
++
++    /**
++     * Whether this LRUMap will scan until a removable entry is found when the
++     * map is full.
++     *
++     * @return true if this map scans
++     * @since Commons Collections 3.1
++     */
++    public boolean isScanUntilRemovable() {
++        return scanUntilRemovable;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Clones the map without cloning the keys or values.
++     *
++     * @return a shallow clone
++     */
++    public Object clone() {
++        return super.clone();
++    }
++
++    /**
++     * Write the map out using a custom routine.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        doWriteObject(out);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        doReadObject(in);
++    }
++
++    /**
++     * Writes the data necessary for <code>put()</code> to work in deserialization.
++     */
++    protected void doWriteObject(ObjectOutputStream out) throws IOException {
++        out.writeInt(maxSize);
++        super.doWriteObject(out);
++    }
++
++    /**
++     * Reads the data necessary for <code>put()</code> to work in the superclass.
++     */
++    protected void doReadObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        maxSize = in.readInt();
++        super.doReadObject(in);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/LazyMap.java
+@@ -0,0 +1,167 @@
++// GenericsNote: Converted -- Using a Transformer instead of a Factory is no longer allowed.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Map;
++
++import org.apache.commons.collections15.Factory;
++import org.apache.commons.collections15.Transformer;
++import org.apache.commons.collections15.functors.FactoryTransformer;
++
++/**
++ * Decorates another <code>Map</code> to create objects in the map on demand.
++ * <p/>
++ * When the {@link #get(Object)} method is called with a key that does not
++ * exist in the map, the factory is used to create the object. The created
++ * object will be added to the map using the requested key.
++ * <p/>
++ * For instance:
++ * <pre>
++ * Factory factory = new Factory() {
++ *     public Object create() {
++ *         return new Date();
++ *     }
++ * }
++ * Map lazy = Lazy.map(new HashMap(), factory);
++ * Object obj = lazy.get("NOW");
++ * </pre>
++ * <p/>
++ * After the above code is executed, <code>obj</code> will contain
++ * a new <code>Date</code> instance. Furthermore, that <code>Date</code>
++ * instance is mapped to the "NOW" key in the map.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class LazyMap <K,V> extends AbstractMapDecorator<K, V> implements Map<K, V>, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 7990956402564206740L;
++
++    /**
++     * The factory to use to construct elements
++     */
++    //protected final Factory<V> factory;
++
++    /**
++     * The factory to use to construct elements
++     */
++    protected final Transformer<K, V> transformer;
++
++    /**
++     * Factory method to create a lazily instantiated map.
++     *
++     * @param map     the map to decorate, must not be null
++     * @param factory the factory to use, must not be null
++     * @throws IllegalArgumentException if map or factory is null
++     */
++    public static <K,V> Map<K, V> decorate(Map<K, V> map, Factory<V> factory) {
++        return new LazyMap<K, V>(map, factory);
++    }
++
++    /**
++     * Factory method to create a lazily instantiated map.
++     *
++     * @param map     		Map to decorate, must not be null
++     * @param transformer	Transformer to use, must not be null
++     * @throws IllegalArgumentException if map or transformer is null
++     */
++    public static <K,V> Map<K, V> decorate(Map<K, V> map, Transformer<K, V> transformer) {
++        return new LazyMap<K, V>(map, transformer);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map     the map to decorate, must not be null
++     * @param factory the factory to use, must not be null
++     * @throws IllegalArgumentException if map or factory is null
++     */
++    protected LazyMap(Map<K, V> map, Factory<V> factory) {
++        super(map);
++        if (factory == null) {
++            throw new IllegalArgumentException("Factory must not be null");
++        }
++        this.transformer = new FactoryTransformer<K, V>(factory);
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map     		Map to decorate, must not be null
++     * @param transformer	Transformer to use, must not be null
++     * @throws IllegalArgumentException if map or factory is null
++     */
++    protected LazyMap(Map<K, V> map, Transformer<K, V> transformer) {
++        super(map);
++        if (transformer == null) {
++            throw new IllegalArgumentException("Transformer must not be null");
++        }
++        this.transformer = transformer;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     * @since Commons Collections 3.1
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(map);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     * @since Commons Collections 3.1
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        map = (Map<K, V>) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    public V get(Object key) {
++        // create value for key if key is not currently in the map
++        if (map.containsKey(key) == false) {
++            V value = this.transformer.transform((K) key);
++            map.put((K) key, value);
++            return value;
++        }
++        return map.get(key);
++    }
++
++    // no need to wrap keySet, entrySet or values as they are views of
++    // existing map entries - you can't do a map-style get on them.
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/LazySortedMap.java
+@@ -0,0 +1,144 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import java.util.Comparator;
++import java.util.SortedMap;
++
++import org.apache.commons.collections15.Factory;
++import org.apache.commons.collections15.Transformer;
++
++/**
++ * Decorates another <code>SortedMap</code> to create objects in the map on demand.
++ * <p/>
++ * When the {@link #get(Object)} method is called with a key that does not
++ * exist in the map, the factory is used to create the object. The created
++ * object will be added to the map using the requested key.
++ * <p/>
++ * For instance:
++ * <pre>
++ * Factory factory = new Factory() {
++ *     public Object create() {
++ *         return new Date();
++ *     }
++ * }
++ * SortedMap lazy = Lazy.sortedMap(new HashMap(), factory);
++ * Object obj = lazy.get("NOW");
++ * </pre>
++ * <p/>
++ * After the above code is executed, <code>obj</code> will contain
++ * a new <code>Date</code> instance. Furthermore, that <code>Date</code>
++ * instance is mapped to the "NOW" key in the map.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class LazySortedMap <K,V> extends LazyMap<K, V> implements SortedMap<K, V> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 2715322183617658933L;
++
++    /**
++     * Factory method to create a lazily instantiated sorted map.
++     *
++     * @param map     the map to decorate, must not be null
++     * @param factory the factory to use, must not be null
++     * @throws IllegalArgumentException if map or factory is null
++     */
++    public static <K,V> SortedMap<K, V> decorate(SortedMap<K, V> map, Factory<V> factory) {
++        return new LazySortedMap<K, V>(map, factory);
++    }
++
++    /**
++     * Factory method to create a lazily instantiated sorted map.
++     *
++     * @param map     		Map to decorate, must not be null
++     * @param transformer	Transformer to use, must not be null
++     * @throws IllegalArgumentException if map or transformer is null
++     */
++    public static <K,V> SortedMap<K, V> decorate(SortedMap<K, V> map, Transformer<K, V> transformer) {
++        return new LazySortedMap<K, V>(map, transformer);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map     the map to decorate, must not be null
++     * @param factory the factory to use, must not be null
++     * @throws IllegalArgumentException if map or factory is null
++     */
++    protected LazySortedMap(SortedMap<K, V> map, Factory<V> factory) {
++        super(map, factory);
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map     		Map to decorate, must not be null
++     * @param transformer	Transformer to use, must not be null
++     * @throws IllegalArgumentException if map or transformer is null
++     */
++    protected LazySortedMap(SortedMap<K, V> map, Transformer<K, V> transformer) {
++        super(map, transformer);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the map being decorated.
++     *
++     * @return the decorated map
++     */
++    protected SortedMap<K, V> getSortedMap() {
++        return (SortedMap<K, V>) map;
++    }
++
++    //-----------------------------------------------------------------------
++    public K firstKey() {
++        return getSortedMap().firstKey();
++    }
++
++    public K lastKey() {
++        return getSortedMap().lastKey();
++    }
++
++    public Comparator<? super K> comparator() {
++        return getSortedMap().comparator();
++    }
++
++    public SortedMap<K, V> subMap(K fromKey, K toKey) {
++        SortedMap<K, V> map = getSortedMap().subMap(fromKey, toKey);
++        return new LazySortedMap<K, V>(map, transformer);
++    }
++
++    public SortedMap<K, V> headMap(K toKey) {
++        SortedMap<K, V> map = getSortedMap().headMap(toKey);
++        return new LazySortedMap<K, V>(map, transformer);
++    }
++
++    public SortedMap<K, V> tailMap(K fromKey) {
++        SortedMap<K, V> map = getSortedMap().tailMap(fromKey);
++        return new LazySortedMap<K, V>(map, transformer);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/LinkedMap.java
+@@ -0,0 +1,276 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.iterators.UnmodifiableIterator;
++import org.apache.commons.collections15.iterators.UnmodifiableListIterator;
++import org.apache.commons.collections15.list.UnmodifiableList;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.*;
++
++/**
++ * A <code>Map</code> implementation that maintains the order of the entries.
++ * In this implementation order is maintained by original insertion.
++ * <p/>
++ * This implementation improves on the JDK1.4 LinkedHashMap by adding the
++ * {@link org.apache.commons.collections15.MapIterator MapIterator}
++ * functionality, additional convenience methods and allowing
++ * bidirectional iteration. It also implements <code>OrderedMap</code>.
++ * In addition, non-interface methods are provided to access the map by index.
++ * <p/>
++ * The <code>orderedMapIterator()</code> method provides direct access to a
++ * bidirectional iterator. The iterators from the other views can also be cast
++ * to <code>OrderedIterator</code> if required.
++ * <p/>
++ * All the available iterators can be reset back to the start by casting to
++ * <code>ResettableIterator</code> and calling <code>reset()</code>.
++ * <p/>
++ * The implementation is also designed to be subclassed, with lots of useful
++ * methods exposed.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class LinkedMap <K,V> extends AbstractLinkedMap<K, V> implements Serializable, Cloneable {
++
++    /**
++     * Serialisation version
++     */
++    private static final long serialVersionUID = 9077234323521161066L;
++
++    /**
++     * Constructs a new empty map with default size and load factor.
++     */
++    public LinkedMap() {
++        super(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_THRESHOLD);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity.
++     *
++     * @param initialCapacity the initial capacity
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     */
++    public LinkedMap(int initialCapacity) {
++        super(initialCapacity);
++    }
++
++    /**
++     * Constructs a new, empty map with the specified initial capacity and
++     * load factor.
++     *
++     * @param initialCapacity the initial capacity
++     * @param loadFactor      the load factor
++     * @throws IllegalArgumentException if the initial capacity is less than one
++     * @throws IllegalArgumentException if the load factor is less than zero
++     */
++    public LinkedMap(int initialCapacity, float loadFactor) {
++        super(initialCapacity, loadFactor);
++    }
++
++    /**
++     * Constructor copying elements from another map.
++     *
++     * @param map the map to copy
++     * @throws NullPointerException if the map is null
++     */
++    public LinkedMap(Map<? extends K, ? extends V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Clones the map without cloning the keys or values.
++     *
++     * @return a shallow clone
++     */
++    public Object clone() {
++        return super.clone();
++    }
++
++    /**
++     * Write the map out using a custom routine.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        doWriteObject(out);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        doReadObject(in);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the key at the specified index.
++     *
++     * @param index the index to retrieve
++     * @return the key at the specified index
++     * @throws IndexOutOfBoundsException if the index is invalid
++     */
++    public K get(int index) {
++        return getEntry(index).getKey();
++    }
++
++    /**
++     * Gets the value at the specified index.
++     *
++     * @param index the index to retrieve
++     * @return the key at the specified index
++     * @throws IndexOutOfBoundsException if the index is invalid
++     */
++    public V getValue(int index) {
++        return getEntry(index).getValue();
++    }
++
++    /**
++     * Gets the index of the specified key.
++     *
++     * @param key the key to find the index of
++     * @return the index, or -1 if not found
++     */
++    public int indexOf(Object key) {
++        int i = 0;
++        for (LinkEntry entry = header.after; entry != header; entry = entry.after, i++) {
++            if (isEqualKey(key, entry.getKey())) {
++                return i;
++            }
++        }
++        return -1;
++    }
++
++    /**
++     * Removes the element at the specified index.
++     *
++     * @param index the index of the object to remove
++     * @return the previous value corresponding the <code>key</code>,
++     *         or <code>null</code> if none existed
++     * @throws IndexOutOfBoundsException if the index is invalid
++     */
++    public V remove(int index) {
++        return remove(get(index));
++    }
++
++    /**
++     * Gets an unmodifiable List view of the keys.
++     * <p/>
++     * The returned list is unmodifiable because changes to the values of
++     * the list (using {@link java.util.ListIterator#set(Object)}) will
++     * effectively remove the value from the list and reinsert that value at
++     * the end of the list, which is an unexpected side effect of changing the
++     * value of a list.  This occurs because changing the key, changes when the
++     * mapping is added to the map and thus where it appears in the list.
++     * <p/>
++     * An alternative to this method is to use {@link #keySet()}.
++     *
++     * @return The ordered list of keys.
++     * @see #keySet()
++     */
++    public List<K> asList() {
++        return new LinkedMapList<K, V>(this);
++    }
++
++    /**
++     * List view of map.
++     */
++    static class LinkedMapList <K,V> extends AbstractList<K> {
++
++        final LinkedMap<K, V> parent;
++
++        LinkedMapList(LinkedMap<K, V> parent) {
++            this.parent = parent;
++        }
++
++        public int size() {
++            return parent.size();
++        }
++
++        public K get(int index) {
++            return parent.get(index);
++        }
++
++        public boolean contains(Object obj) {
++            return parent.containsKey(obj);
++        }
++
++        public int indexOf(Object obj) {
++            return parent.indexOf(obj);
++        }
++
++        public int lastIndexOf(Object obj) {
++            return parent.indexOf(obj);
++        }
++
++        public boolean containsAll(Collection<?> coll) {
++            return parent.keySet().containsAll(coll);
++        }
++
++        public K remove(int index) {
++            throw new UnsupportedOperationException();
++        }
++
++        public boolean remove(Object obj) {
++            throw new UnsupportedOperationException();
++        }
++
++        public boolean removeAll(Collection<?> coll) {
++            throw new UnsupportedOperationException();
++        }
++
++        public boolean retainAll(Collection<?> coll) {
++            throw new UnsupportedOperationException();
++        }
++
++        public void clear() {
++            throw new UnsupportedOperationException();
++        }
++
++        public Object[] toArray() {
++            return parent.keySet().toArray();
++        }
++
++        public <T> T[] toArray(T[] array) {
++            return parent.keySet().toArray(array);
++        }
++
++        public Iterator<K> iterator() {
++            return UnmodifiableIterator.decorate(parent.keySet().iterator());
++        }
++
++        public ListIterator<K> listIterator() {
++            return UnmodifiableListIterator.decorate(super.listIterator());
++        }
++
++        public ListIterator<K> listIterator(int fromIndex) {
++            return UnmodifiableListIterator.decorate(super.listIterator(fromIndex));
++        }
++
++        public List<K> subList(int fromIndexInclusive, int toIndexExclusive) {
++            return UnmodifiableList.decorate(super.subList(fromIndexInclusive, toIndexExclusive));
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/ListOrderedMap.java
+@@ -0,0 +1,592 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.OrderedMap;
++import org.apache.commons.collections15.OrderedMapIterator;
++import org.apache.commons.collections15.ResettableIterator;
++import org.apache.commons.collections15.iterators.AbstractIteratorDecorator;
++import org.apache.commons.collections15.keyvalue.AbstractMapEntry;
++import org.apache.commons.collections15.list.UnmodifiableList;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.*;
++
++/**
++ * Decorates a <code>Map</code> to ensure that the order of addition is retained
++ * using a <code>List</code> to maintain order.
++ * <p/>
++ * The order will be used via the iterators and toArray methods on the views.
++ * The order is also returned by the <code>MapIterator</code>.
++ * The <code>orderedMapIterator()</code> method accesses an iterator that can
++ * iterate both forwards and backwards through the map.
++ * In addition, non-interface methods are provided to access the map by index.
++ * <p/>
++ * If an object is added to the Map for a second time, it will remain in the
++ * original position in the iteration.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Henri Yandell
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class ListOrderedMap <K,V> extends AbstractMapDecorator<K, V> implements OrderedMap<K, V>, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 2728177751851003750L;
++
++    /**
++     * Internal list to hold the sequence of objects
++     */
++    protected final List<K> insertOrder = new ArrayList<K>();
++
++    /**
++     * Factory method to create an ordered map.
++     * <p/>
++     * An <code>ArrayList</code> is used to retain order.
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    public static <K,V> OrderedMap<K, V> decorate(Map<K, V> map) {
++        return new ListOrderedMap<K, V>(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructs a new empty <code>ListOrderedMap</code> that decorates
++     * a <code>HashMap</code>.
++     *
++     * @since Commons Collections 3.1
++     */
++    public ListOrderedMap() {
++        this(new HashMap<K, V>());
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    protected ListOrderedMap(Map<K, V> map) {
++        super(map);
++        insertOrder.addAll(getMap().keySet());
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     * @since Commons Collections 3.1
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(map);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     * @since Commons Collections 3.1
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        map = (Map<K, V>) in.readObject();
++    }
++
++    // Implement OrderedMap
++    //-----------------------------------------------------------------------
++    public MapIterator<K, V> mapIterator() {
++        return orderedMapIterator();
++    }
++
++    public OrderedMapIterator<K, V> orderedMapIterator() {
++        return new ListOrderedMapIterator<K, V>(this);
++    }
++
++    /**
++     * Gets the first key in this map by insert order.
++     *
++     * @return the first key currently in this map
++     * @throws NoSuchElementException if this map is empty
++     */
++    public K firstKey() {
++        if (size() == 0) {
++            throw new NoSuchElementException("Map is empty");
++        }
++        return insertOrder.get(0);
++    }
++
++    /**
++     * Gets the last key in this map by insert order.
++     *
++     * @return the last key currently in this map
++     * @throws NoSuchElementException if this map is empty
++     */
++    public K lastKey() {
++        if (size() == 0) {
++            throw new NoSuchElementException("Map is empty");
++        }
++        return insertOrder.get(size() - 1);
++    }
++
++    /**
++     * Gets the next key to the one specified using insert order.
++     * This method performs a list search to find the key and is O(n).
++     *
++     * @param key the key to find previous for
++     * @return the next key, null if no match or at start
++     */
++    public K nextKey(K key) {
++        int index = insertOrder.indexOf(key);
++        if (index >= 0 && index < size() - 1) {
++            return insertOrder.get(index + 1);
++        }
++        return null;
++    }
++
++    /**
++     * Gets the previous key to the one specified using insert order.
++     * This method performs a list search to find the key and is O(n).
++     *
++     * @param key the key to find previous for
++     * @return the previous key, null if no match or at start
++     */
++    public K previousKey(K key) {
++        int index = insertOrder.indexOf(key);
++        if (index > 0) {
++            return insertOrder.get(index - 1);
++        }
++        return null;
++    }
++
++    //-----------------------------------------------------------------------
++    public V put(K key, V value) {
++        if (getMap().containsKey(key)) {
++            // re-adding doesn't change order
++            return getMap().put(key, value);
++        } else {
++            // first add, so add to both map and list
++            V result = getMap().put(key, value);
++            insertOrder.add(key);
++            return result;
++        }
++    }
++
++    public void putAll(Map<? extends K, ? extends V> map) {
++        for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
++            Map.Entry entry = (Map.Entry) it.next();
++            put((K) entry.getKey(), (V) entry.getValue());
++        }
++    }
++
++    public V remove(Object key) {
++        V result = getMap().remove(key);
++        insertOrder.remove(key);
++        return result;
++    }
++
++    public void clear() {
++        getMap().clear();
++        insertOrder.clear();
++    }
++
++    //-----------------------------------------------------------------------
++    public Set<K> keySet() {
++        return new KeySetView<K, V>(this);
++    }
++
++    public Collection<V> values() {
++        return new ValuesView<K, V>(this);
++    }
++
++    public Set<Map.Entry<K,V>> entrySet() {
++        return new EntrySetView<K,V>(this, this.insertOrder);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Returns the Map as a string.
++     *
++     * @return the Map as a String
++     */
++    public String toString() {
++        if (isEmpty()) {
++            return "{}";
++        }
++        StringBuffer buf = new StringBuffer();
++        buf.append('{');
++        boolean first = true;
++        Iterator it = entrySet().iterator();
++        while (it.hasNext()) {
++            Map.Entry entry = (Map.Entry) it.next();
++            Object key = entry.getKey();
++            Object value = entry.getValue();
++            if (first) {
++                first = false;
++            } else {
++                buf.append(", ");
++            }
++            buf.append(key == this ? "(this Map)" : key);
++            buf.append('=');
++            buf.append(value == this ? "(this Map)" : value);
++        }
++        buf.append('}');
++        return buf.toString();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the key at the specified index.
++     *
++     * @param index the index to retrieve
++     * @return the key at the specified index
++     * @throws IndexOutOfBoundsException if the index is invalid
++     */
++    public K get(int index) {
++        return insertOrder.get(index);
++    }
++
++    /**
++     * Gets the value at the specified index.
++     *
++     * @param index the index to retrieve
++     * @return the key at the specified index
++     * @throws IndexOutOfBoundsException if the index is invalid
++     */
++    public V getValue(int index) {
++        return get(insertOrder.get(index));
++    }
++
++    /**
++     * Gets the index of the specified key.
++     *
++     * @param key the key to find the index of
++     * @return the index, or -1 if not found
++     */
++    public int indexOf(Object key) {
++        return insertOrder.indexOf(key);
++    }
++
++    /**
++     * Removes the element at the specified index.
++     *
++     * @param index the index of the object to remove
++     * @return the previous value corresponding the <code>key</code>,
++     *         or <code>null</code> if none existed
++     * @throws IndexOutOfBoundsException if the index is invalid
++     */
++    public Object remove(int index) {
++        return remove(get(index));
++    }
++
++    /**
++     * Gets an unmodifiable List view of the keys which changes as the map changes.
++     * <p/>
++     * The returned list is unmodifiable because changes to the values of
++     * the list (using {@link java.util.ListIterator#set(Object)}) will
++     * effectively remove the value from the list and reinsert that value at
++     * the end of the list, which is an unexpected side effect of changing the
++     * value of a list.  This occurs because changing the key, changes when the
++     * mapping is added to the map and thus where it appears in the list.
++     * <p/>
++     * An alternative to this method is to use {@link #keySet()}.
++     *
++     * @return The ordered list of keys.
++     * @see #keySet()
++     */
++    public List<K> asList() {
++        return UnmodifiableList.decorate(insertOrder);
++    }
++
++    //-----------------------------------------------------------------------
++    static class ValuesView <K,V> extends AbstractCollection<V> {
++        private final ListOrderedMap<K, V> parent;
++
++        ValuesView(ListOrderedMap<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public int size() {
++            return this.parent.size();
++        }
++
++        public boolean contains(Object value) {
++            return this.parent.containsValue(value);
++        }
++
++        public void clear() {
++            this.parent.clear();
++        }
++
++        public Iterator<V> iterator() {
++            return new AbstractIteratorDecorator(parent.entrySet().iterator()) {
++                public Object next() {
++                    return ((Map.Entry) iterator.next()).getValue();
++                }
++            };
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    static class KeySetView <K,V> extends AbstractSet<K> {
++        private final ListOrderedMap<K, V> parent;
++
++        KeySetView(ListOrderedMap<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public int size() {
++            return this.parent.size();
++        }
++
++        public boolean contains(Object value) {
++            return this.parent.containsKey(value);
++        }
++
++        public void clear() {
++            this.parent.clear();
++        }
++
++        public Iterator<K> iterator() {
++            final Iterator<Map.Entry<K, V>> entryIterator = parent.entrySet().iterator();
++            return new Iterator<K>() {
++                public K next() {
++                    return entryIterator.next().getKey();
++                }
++
++                public boolean hasNext() {
++                    return entryIterator.hasNext();
++                }
++
++                public void remove() {
++                    entryIterator.remove();
++                }
++            };
++        }
++    }
++
++    //-----------------------------------------------------------------------    
++    static class EntrySetView <K,V> extends AbstractSet<Map.Entry<K, V>> {
++        private final ListOrderedMap<K, V> parent;
++        private final List<K> insertOrder;
++        private Set<Map.Entry<K, V>> entrySet;
++
++        public EntrySetView(ListOrderedMap<K, V> parent, List<K> insertOrder) {
++            super();
++            this.parent = parent;
++            this.insertOrder = insertOrder;
++        }
++
++        private Set<Map.Entry<K, V>> getEntrySet() {
++            if (entrySet == null) {
++                entrySet = parent.getMap().entrySet();
++            }
++            return entrySet;
++        }
++
++        public int size() {
++            return this.parent.size();
++        }
++
++        public boolean isEmpty() {
++            return this.parent.isEmpty();
++        }
++
++        public boolean contains(Object obj) {
++            return getEntrySet().contains(obj);
++        }
++
++        public boolean containsAll(Collection<?> coll) {
++            return getEntrySet().containsAll(coll);
++        }
++
++        public boolean remove(Object obj) {
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++            if (getEntrySet().contains(obj)) {
++                Object key = ((Map.Entry) obj).getKey();
++                parent.remove(key);
++                return true;
++            }
++            return false;
++        }
++
++        public void clear() {
++            this.parent.clear();
++        }
++
++        public boolean equals(Object obj) {
++            if (obj == this) {
++                return true;
++            }
++            return getEntrySet().equals(obj);
++        }
++
++        public int hashCode() {
++            return getEntrySet().hashCode();
++        }
++
++        public String toString() {
++            return getEntrySet().toString();
++        }
++
++        public Iterator<Map.Entry<K, V>> iterator() {
++            return new ListOrderedIterator<K, V>(parent, insertOrder);
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    static class ListOrderedIterator <K,V> implements Iterator<Map.Entry<K, V>> {
++        private final ListOrderedMap<K, V> parent;
++        private K last = null;
++        private Iterator<K> listIterator;
++
++        ListOrderedIterator(ListOrderedMap<K, V> parent, List<K> insertOrder) {
++            listIterator = insertOrder.iterator();
++            this.parent = parent;
++        }
++
++        public Map.Entry<K, V> next() {
++            last = listIterator.next();
++            return new ListOrderedMapEntry<K, V>(parent, last);
++        }
++
++        public void remove() {
++            listIterator.remove();
++            parent.getMap().remove(last);
++        }
++
++        public boolean hasNext() {
++            return listIterator.hasNext();
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    static class ListOrderedMapEntry <K,V> extends AbstractMapEntry<K, V> {
++        private final ListOrderedMap<K, V> parent;
++
++        ListOrderedMapEntry(ListOrderedMap<K, V> parent, K key) {
++            super(key, null);
++            this.parent = parent;
++        }
++
++        public V getValue() {
++            return parent.get(key);
++        }
++
++        public V setValue(V value) {
++            return parent.getMap().put(key, value);
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    static class ListOrderedMapIterator <K,V> implements OrderedMapIterator<K, V>, ResettableIterator<K> {
++        private final ListOrderedMap<K, V> parent;
++        private ListIterator<K> iterator;
++        private K last = null;
++        private boolean readable = false;
++
++        ListOrderedMapIterator(ListOrderedMap<K, V> parent) {
++            super();
++            this.parent = parent;
++            this.iterator = parent.insertOrder.listIterator();
++        }
++
++        public boolean hasNext() {
++            return iterator.hasNext();
++        }
++
++        public K next() {
++            last = iterator.next();
++            readable = true;
++            return last;
++        }
++
++        public boolean hasPrevious() {
++            return iterator.hasPrevious();
++        }
++
++        public K previous() {
++            last = iterator.previous();
++            readable = true;
++            return last;
++        }
++
++        public void remove() {
++            if (readable == false) {
++                throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
++            }
++            iterator.remove();
++            parent.map.remove(last);
++            readable = false;
++        }
++
++        public K getKey() {
++            if (readable == false) {
++                throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
++            }
++            return last;
++        }
++
++        public V getValue() {
++            if (readable == false) {
++                throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
++            }
++            return parent.get(last);
++        }
++
++        public V setValue(V value) {
++            if (readable == false) {
++                throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
++            }
++            return parent.map.put(last, value);
++        }
++
++        public void reset() {
++            iterator = parent.insertOrder.listIterator();
++            last = null;
++            readable = false;
++        }
++
++        public String toString() {
++            if (readable == true) {
++                return "Iterator[" + getKey() + "=" + getValue() + "]";
++            } else {
++                return "Iterator[]";
++            }
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/MultiKeyMap.java
+@@ -0,0 +1,488 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.IterableMap;
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.keyvalue.MultiKey;
++
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * A <code>Map</code> implementation that uses multiple keys to map the value.
++ * <p/>
++ * This class is the most efficient way to uses multiple keys to map to a value.
++ * The best way to use this class is via the additional map-style methods.
++ * These provide <code>get</code>, <code>containsKey</code>, <code>put</code> and
++ * <code>remove</code> for individual keys which operate without extra object creation.
++ * <p/>
++ * The additional methods are the main interface of this map.
++ * As such, you will not normally hold this map in a variable of type <code>Map</code>.
++ * <p/>
++ * The normal map methods take in and return a {@link MultiKey}.
++ * If you try to use <code>put()</code> with any other object type a
++ * <code>ClassCastException</code> is thrown. If you try to use <code>null</code> as
++ * the key in <code>put()</code> a <code>NullPointerException</code> is thrown.
++ * <p/>
++ * This map is implemented as a decorator of a <code>AbstractHashedMap</code> which
++ * enables extra behaviour to be added easily.
++ * <ul>
++ * <li><code>MultiKeyMap.decorate(new LinkedMap())</code> creates an ordered map.
++ * <li><code>MultiKeyMap.decorate(new LRUMap())</code> creates an least recently used map.
++ * <li><code>MultiKeyMap.decorate(new ReferenceMap())</code> creates a garbage collector sensitive map.
++ * </ul>
++ * Note that <code>IdentityMap</code> and <code>ReferenceIdentityMap</code> are unsuitable
++ * for use as the key comparison would work on the whole MultiKey, not the elements within.
++ * <p/>
++ * As an example, consider a least recently used cache that uses a String airline code
++ * and a Locale to lookup the airline's name:
++ * <pre>
++ * private MultiKeyMap cache = MultiKeyMap.decorate(new LRUMap(50));
++ * <p/>
++ * public String getAirlineName(String code, String locale) {
++ *   String name = (String) cache.get(code, locale);
++ *   if (name == null) {
++ *     name = getAirlineNameFromDB(code, locale);
++ *     cache.put(code, locale, name);
++ *   }
++ *   return name;
++ * }
++ * </pre>
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.1
++ */
++public class MultiKeyMap <K,V> implements IterableMap<MultiKey<K>, V>, Serializable {
++
++    /**
++     * Serialisation version
++     */
++    private static final long serialVersionUID = -1788199231038721040L;
++
++    /**
++     * The decorated map
++     */
++    protected final AbstractHashedMap<MultiKey<K>, V> map;
++
++    //-----------------------------------------------------------------------
++    /**
++     * Decorates the specified map to add the MultiKeyMap API and fast query.
++     * The map must not be null and must be empty.
++     *
++     * @param map the map to decorate, not null
++     * @throws IllegalArgumentException if the map is null or not empty
++     */
++    public static <K,V> MultiKeyMap<K, V> decorate(AbstractHashedMap<MultiKey<K>, V> map) {
++        if (map == null) {
++            throw new IllegalArgumentException("Map must not be null");
++        }
++        if (map.size() > 0) {
++            throw new IllegalArgumentException("Map must be empty");
++        }
++        return new MultiKeyMap<K, V>(map);
++    }
++
++    //-----------------------------------------------------------------------    
++    /**
++     * Constructs a new MultiKeyMap that decorates a <code>HashedMap</code>.
++     */
++    public MultiKeyMap() {
++        super();
++        map = new HashedMap<MultiKey<K>, V>();
++    }
++
++    /**
++     * Constructor that decorates the specified map and is called from
++     * {@link #decorate(AbstractHashedMap)}.
++     * The map must not be null and should be empty or only contain valid keys.
++     * This constructor performs no validation.
++     *
++     * @param map the map to decorate
++     */
++    protected MultiKeyMap(AbstractHashedMap<MultiKey<K>, V> map) {
++        super();
++        this.map = map;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the value mapped to the specified multi-key.
++     *
++     * @param keys the keys
++     * @return the mapped value, null if no match
++     */
++    public V get(K... keys) {
++        int hashCode = hash(keys);
++        AbstractHashedMap.HashEntry<MultiKey<K>, V> entry = map.data[map.hashIndex(hashCode, map.data.length)];
++        while (entry != null) {
++            if (entry.hashCode == hashCode && isEqualKey(entry, keys)) {
++                return entry.getValue();
++            }
++            entry = entry.next;
++        }
++        return null;
++    }
++
++    /**
++     * Checks whether the map contains the specified multi-key.
++     *
++     * @param keys the keys
++     * @return true if the map contains the key
++     */
++    public boolean containsKey(K... keys) {
++        int hashCode = hash(keys);
++        AbstractHashedMap.HashEntry<MultiKey<K>, V> entry = map.data[map.hashIndex(hashCode, map.data.length)];
++        while (entry != null) {
++            if (entry.hashCode == hashCode && isEqualKey(entry, keys)) {
++                return true;
++            }
++            entry = entry.next;
++        }
++        return false;
++    }
++
++    /**
++     * For backwards compatibility, makes a call to the new varargs {@link MultiKeyMap#putMultiKey}
++     */
++    public V put(K key1, K key2, V value) {
++        return putMultiKey(value, key1, key2);
++    }
++
++    /**
++     * For backwards compatibility, makes a call to the new varargs {@link MultiKeyMap#putMultiKey}
++     */
++    public V put(K key1, K key2, K key3, V value) {
++        return putMultiKey(value, key1, key2, key3);
++    }
++
++    /**
++     * For backwards compatibility, makes a call to the new varargs {@link MultiKeyMap#putMultiKey}
++     */
++    public V put(K key1, K key2, K key3, K key4, V value) {
++        return putMultiKey(value, key1, key2, key3, key4);
++    }
++
++    /**
++     * For backwards compatibility, makes a call to the new varargs {@link MultiKeyMap#putMultiKey}
++     */
++    public V put(K key1, K key2, K key3, K key4, K key5, V value) {
++        return putMultiKey(value, key1, key2, key3, key4, key5);
++    }
++
++    /**
++     * Stores the value against the specified multi-key.
++     *
++     * @param value the value to store
++     * @param keys  the keys
++     * @return the value previously mapped to this combined key, null if none
++     */
++    public V putMultiKey(V value, K... keys) {
++        int hashCode = hash(keys);
++        int index = map.hashIndex(hashCode, map.data.length);
++        AbstractHashedMap.HashEntry<MultiKey<K>, V> entry = map.data[index];
++        while (entry != null) {
++            if (entry.hashCode == hashCode && isEqualKey(entry, keys)) {
++                V oldValue = entry.getValue();
++                map.updateEntry(entry, value);
++                return oldValue;
++            }
++            entry = entry.next;
++        }
++
++        map.addMapping(index, hashCode, new MultiKey<K>(keys), value);
++        return null;
++    }
++
++    /**
++     * Removes the specified multi-key from this map.
++     *
++     * @param keys the keys
++     * @return the value mapped to the removed key, null if key not in map
++     */
++    public Object remove(K... keys) {
++        int hashCode = hash(keys);
++        int index = map.hashIndex(hashCode, map.data.length);
++        AbstractHashedMap.HashEntry<MultiKey<K>, V> entry = map.data[index];
++        AbstractHashedMap.HashEntry<MultiKey<K>, V> previous = null;
++        while (entry != null) {
++            if (entry.hashCode == hashCode && isEqualKey(entry, keys)) {
++                Object oldValue = entry.getValue();
++                map.removeMapping(entry, index, previous);
++                return oldValue;
++            }
++            previous = entry;
++            entry = entry.next;
++        }
++        return null;
++    }
++
++    /**
++     * Gets the hash code for the specified multi-key.
++     *
++     * @param keys the keys
++     * @return the hash code
++     */
++    protected int hash(K... keys) {
++        int h = 0;
++        for (int i = 0; i < keys.length; i++) {
++            K key = keys[i];
++            if (key != null) {
++                h ^= key.hashCode();
++            }
++        }
++        h += ~(h << 9);
++        h ^= (h >>> 14);
++        h += (h << 4);
++        h ^= (h >>> 10);
++        return h;
++    }
++
++    /**
++     * Is the key equal to the combined key.
++     *
++     * @param entry the entry to compare to
++     * @param keys  the keys
++     * @return true if the key matches
++     */
++    protected boolean isEqualKey(AbstractHashedMap.HashEntry<MultiKey<K>, V> entry, K... keys) {
++        MultiKey multi = (MultiKey) entry.getKey();
++        if (multi.size() != keys.length) {
++            return false;
++        } else {
++            for (int i = 0; i < keys.length; i++) {
++                K key = keys[i];
++                if ((key == null ? multi.getKey(i) != null : !key.equals(multi.getKey(i)))) {
++                    return false;
++                }
++            }
++        }
++        return true;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Removes all mappings where the first key is that specified.
++     * <p/>
++     * This method removes all the mappings where the <code>MultiKey</code>
++     * has one or more keys, and the first matches that specified.
++     *
++     * @param key1 the first key
++     * @return true if any elements were removed
++     */
++    public boolean removeAll(Object key1) {
++        boolean modified = false;
++        MapIterator it = mapIterator();
++        while (it.hasNext()) {
++            MultiKey multi = (MultiKey) it.next();
++            if (multi.size() >= 1 && (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0)))) {
++                it.remove();
++                modified = true;
++            }
++        }
++        return modified;
++    }
++
++    /**
++     * Removes all mappings where the first two keys are those specified.
++     * <p/>
++     * This method removes all the mappings where the <code>MultiKey</code>
++     * has two or more keys, and the first two match those specified.
++     *
++     * @param key1 the first key
++     * @param key2 the second key
++     * @return true if any elements were removed
++     */
++    public boolean removeAll(Object key1, Object key2) {
++        boolean modified = false;
++        MapIterator it = mapIterator();
++        while (it.hasNext()) {
++            MultiKey multi = (MultiKey) it.next();
++            if (multi.size() >= 2 && (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) && (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1)))) {
++                it.remove();
++                modified = true;
++            }
++        }
++        return modified;
++    }
++
++    /**
++     * Removes all mappings where the first three keys are those specified.
++     * <p/>
++     * This method removes all the mappings where the <code>MultiKey</code>
++     * has three or more keys, and the first three match those specified.
++     *
++     * @param key1 the first key
++     * @param key2 the second key
++     * @param key3 the third key
++     * @return true if any elements were removed
++     */
++    public boolean removeAll(Object key1, Object key2, Object key3) {
++        boolean modified = false;
++        MapIterator it = mapIterator();
++        while (it.hasNext()) {
++            MultiKey multi = (MultiKey) it.next();
++            if (multi.size() >= 3 && (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) && (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) && (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2)))) {
++                it.remove();
++                modified = true;
++            }
++        }
++        return modified;
++    }
++
++    /**
++     * Removes all mappings where the first four keys are those specified.
++     * <p/>
++     * This method removes all the mappings where the <code>MultiKey</code>
++     * has four or more keys, and the first four match those specified.
++     *
++     * @param key1 the first key
++     * @param key2 the second key
++     * @param key3 the third key
++     * @param key4 the fourth key
++     * @return true if any elements were removed
++     */
++    public boolean removeAll(Object key1, Object key2, Object key3, Object key4) {
++        boolean modified = false;
++        MapIterator it = mapIterator();
++        while (it.hasNext()) {
++            MultiKey multi = (MultiKey) it.next();
++            if (multi.size() >= 4 && (key1 == null ? multi.getKey(0) == null : key1.equals(multi.getKey(0))) && (key2 == null ? multi.getKey(1) == null : key2.equals(multi.getKey(1))) && (key3 == null ? multi.getKey(2) == null : key3.equals(multi.getKey(2))) && (key4 == null ? multi.getKey(3) == null : key4.equals(multi.getKey(3)))) {
++                it.remove();
++                modified = true;
++            }
++        }
++        return modified;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Check to ensure that input keys are valid MultiKey objects.
++     *
++     * @param key the key to check
++     */
++    protected void checkKey(Object key) {
++        if (key == null) {
++            throw new NullPointerException("Key must not be null");
++        }
++    }
++
++    /**
++     * Clones the map without cloning the keys or values.
++     *
++     * @return a shallow clone
++     */
++    public Object clone() {
++        return new MultiKeyMap((AbstractHashedMap) map.clone());
++    }
++
++    /**
++     * Puts the key and value into the map, where the key must be a non-null
++     * MultiKey object.
++     *
++     * @param key   the non-null MultiKey object
++     * @param value the value to store
++     * @return the previous value for the key
++     * @throws NullPointerException if the key is null
++     * @throws ClassCastException   if the key is not a MultiKey
++     */
++    public V put(MultiKey<K> key, V value) {
++        checkKey(key);
++        return map.put(key, value);
++    }
++
++    /**
++     * Puts all the keys and values into this map.
++     * Each key must be non-null and a MultiKey object.
++     *
++     * @param mapToCopy the map to copy in.
++     * @throws NullPointerException if the mapToCopy or any key within is null
++     * @throws ClassCastException   if any key is not a MultiKey
++     */
++    public void putAll(Map<? extends MultiKey<K>, ? extends V> mapToCopy) {
++        for (Iterator it = mapToCopy.keySet().iterator(); it.hasNext();) {
++            Object key = it.next();
++            checkKey(key);
++        }
++        map.putAll(mapToCopy);
++    }
++
++    //-----------------------------------------------------------------------
++    public MapIterator mapIterator() {
++        return map.mapIterator();
++    }
++
++    public int size() {
++        return map.size();
++    }
++
++    public boolean isEmpty() {
++        return map.isEmpty();
++    }
++
++    public boolean containsKey(Object key) {
++        return map.containsKey(key);
++    }
++
++    public boolean containsValue(Object value) {
++        return map.containsValue(value);
++    }
++
++    public V get(Object key) {
++        return map.get(key);
++    }
++
++    public V remove(Object key) {
++        return map.remove(key);
++    }
++
++    public void clear() {
++        map.clear();
++    }
++
++    public Set keySet() {
++        return map.keySet();
++    }
++
++    public Collection values() {
++        return map.values();
++    }
++
++    public Set entrySet() {
++        return map.entrySet();
++    }
++
++    public boolean equals(Object obj) {
++        if (obj == this) {
++            return true;
++        }
++        return map.equals(obj);
++    }
++
++    public int hashCode() {
++        return map.hashCode();
++    }
++
++    public String toString() {
++        return map.toString();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/PredicatedMap.java
+@@ -0,0 +1,184 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Iterator;
++import java.util.Map;
++
++/**
++ * Decorates another <code>Map</code> to validate that additions
++ * match a specified predicate.
++ * <p/>
++ * This map exists to provide validation for the decorated map.
++ * It is normally created to decorate an empty map.
++ * If an object cannot be added to the map, an IllegalArgumentException is thrown.
++ * <p/>
++ * One usage would be to ensure that no null keys are added to the map.
++ * <pre>Map map = PredicatedSet.decorate(new HashMap(), NotNullPredicate.INSTANCE, null);</pre>
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class PredicatedMap <K,V> extends AbstractInputCheckedMapDecorator<K, V> implements Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 7412622456128415156L;
++
++    /**
++     * The key predicate to use
++     */
++    protected final Predicate<? super K> keyPredicate;
++    /**
++     * The value predicate to use
++     */
++    protected final Predicate<? super V> valuePredicate;
++
++    /**
++     * Factory method to create a predicated (validating) map.
++     * <p/>
++     * If there are any elements already in the list being decorated, they
++     * are validated.
++     *
++     * @param map            the map to decorate, must not be null
++     * @param keyPredicate   the predicate to validate the keys, null means no check
++     * @param valuePredicate the predicate to validate to values, null means no check
++     * @throws IllegalArgumentException if the map is null
++     */
++    public static <K,V> Map<K, V> decorate(Map<K, V> map, Predicate<? super K> keyPredicate, Predicate<? super V> valuePredicate) {
++        return new PredicatedMap<K, V>(map, keyPredicate, valuePredicate);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map            the map to decorate, must not be null
++     * @param keyPredicate   the predicate to validate the keys, null means no check
++     * @param valuePredicate the predicate to validate to values, null means no check
++     * @throws IllegalArgumentException if the map is null
++     */
++    protected PredicatedMap(Map<K, V> map, Predicate<? super K> keyPredicate, Predicate<? super V> valuePredicate) {
++        super(map);
++        this.keyPredicate = keyPredicate;
++        this.valuePredicate = valuePredicate;
++
++        Iterator<Map.Entry<K, V>> it = map.entrySet().iterator();
++        while (it.hasNext()) {
++            Map.Entry<K, V> entry = it.next();
++            K key = entry.getKey();
++            V value = entry.getValue();
++            validate(key, value);
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     * @since Commons Collections 3.1
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(map);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     * @since Commons Collections 3.1
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        map = (Map<K, V>) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Validates a key value pair.
++     *
++     * @param key   the key to validate
++     * @param value the value to validate
++     * @throws IllegalArgumentException if invalid
++     */
++    protected void validate(K key, V value) {
++        if (keyPredicate != null && keyPredicate.evaluate(key) == false) {
++            throw new IllegalArgumentException("Cannot add key - Predicate rejected it");
++        }
++        if (valuePredicate != null && valuePredicate.evaluate(value) == false) {
++            throw new IllegalArgumentException("Cannot add value - Predicate rejected it");
++        }
++    }
++
++    /**
++     * Override to validate an object set into the map via <code>setValue</code>.
++     *
++     * @param value the value to validate
++     * @throws IllegalArgumentException if invalid
++     * @since Commons Collections 3.1
++     */
++    protected V checkSetValue(V value) {
++        if (valuePredicate.evaluate(value) == false) {
++            throw new IllegalArgumentException("Cannot set value - Predicate rejected it");
++        }
++        return value;
++    }
++
++    /**
++     * Override to only return true when there is a value transformer.
++     *
++     * @return true if a value predicate is in use
++     * @since Commons Collections 3.1
++     */
++    protected boolean isSetValueChecking() {
++        return (valuePredicate != null);
++    }
++
++    //-----------------------------------------------------------------------
++    public V put(K key, V value) {
++        validate(key, value);
++        return map.put(key, value);
++    }
++
++    public void putAll(Map<? extends K, ? extends V> mapToCopy) {
++        Iterator it = mapToCopy.entrySet().iterator();
++        while (it.hasNext()) {
++            Map.Entry entry = (Map.Entry) it.next();
++            K key = (K) entry.getKey();
++            V value = (V) entry.getValue();
++            validate(key, value);
++        }
++        map.putAll(mapToCopy);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/PredicatedSortedMap.java
+@@ -0,0 +1,115 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.util.Comparator;
++import java.util.SortedMap;
++
++/**
++ * Decorates another <code>SortedMap </code> to validate that additions
++ * match a specified predicate.
++ * <p/>
++ * This map exists to provide validation for the decorated map.
++ * It is normally created to decorate an empty map.
++ * If an object cannot be added to the map, an IllegalArgumentException is thrown.
++ * <p/>
++ * One usage would be to ensure that no null keys are added to the map.
++ * <pre>SortedMap map = PredicatedSortedSet.decorate(new TreeMap(), NotNullPredicate.INSTANCE, null);</pre>
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class PredicatedSortedMap <K,V> extends PredicatedMap<K, V> implements SortedMap<K, V> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 3359846175935304332L;
++
++    /**
++     * Factory method to create a predicated (validating) sorted map.
++     * <p/>
++     * If there are any elements already in the list being decorated, they
++     * are validated.
++     *
++     * @param map            the map to decorate, must not be null
++     * @param keyPredicate   the predicate to validate the keys, null means no check
++     * @param valuePredicate the predicate to validate to values, null means no check
++     * @throws IllegalArgumentException if the map is null
++     */
++    public static <K,V> SortedMap<K, V> decorate(SortedMap<K, V> map, Predicate<? super K> keyPredicate, Predicate<? super V> valuePredicate) {
++        return new PredicatedSortedMap<K, V>(map, keyPredicate, valuePredicate);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map            the map to decorate, must not be null
++     * @param keyPredicate   the predicate to validate the keys, null means no check
++     * @param valuePredicate the predicate to validate to values, null means no check
++     * @throws IllegalArgumentException if the map is null
++     */
++    protected PredicatedSortedMap(SortedMap<K, V> map, Predicate<? super K> keyPredicate, Predicate<? super V> valuePredicate) {
++        super(map, keyPredicate, valuePredicate);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the map being decorated.
++     *
++     * @return the decorated map
++     */
++    protected SortedMap<K, V> getSortedMap() {
++        return (SortedMap<K, V>) map;
++    }
++
++    //-----------------------------------------------------------------------
++    public K firstKey() {
++        return getSortedMap().firstKey();
++    }
++
++    public K lastKey() {
++        return getSortedMap().lastKey();
++    }
++
++    public Comparator<? super K> comparator() {
++        return getSortedMap().comparator();
++    }
++
++    public SortedMap<K, V> subMap(K fromKey, K toKey) {
++        SortedMap<K, V> map = getSortedMap().subMap(fromKey, toKey);
++        return new PredicatedSortedMap<K, V>(map, keyPredicate, valuePredicate);
++    }
++
++    public SortedMap<K, V> headMap(K toKey) {
++        SortedMap map = getSortedMap().headMap(toKey);
++        return new PredicatedSortedMap<K, V>(map, keyPredicate, valuePredicate);
++    }
++
++    public SortedMap<K, V> tailMap(K fromKey) {
++        SortedMap<K, V> map = getSortedMap().tailMap(fromKey);
++        return new PredicatedSortedMap<K, V>(map, keyPredicate, valuePredicate);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/ReferenceIdentityMap.java
+@@ -0,0 +1,212 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.lang.ref.Reference;
++
++/**
++ * A <code>Map</code> implementation that allows mappings to be
++ * removed by the garbage collector and matches keys and values based
++ * on <code>==</code> not <code>equals()</code>.
++ * <p/>
++ * <p/>
++ * When you construct a <code>ReferenceIdentityMap</code>, you can specify what kind
++ * of references are used to store the map's keys and values.
++ * If non-hard references are used, then the garbage collector can remove
++ * mappings if a key or value becomes unreachable, or if the JVM's memory is
++ * running low. For information on how the different reference types behave,
++ * see {@link Reference}.
++ * <p/>
++ * Different types of references can be specified for keys and values.
++ * The default constructor uses hard keys and soft values, providing a
++ * memory-sensitive cache.
++ * <p/>
++ * This map is similar to
++ * {@link org.apache.commons.collections15.map.ReferenceMap ReferenceMap}.
++ * It differs in that keys and values in this class are compared using <code>==</code>.
++ * <p/>
++ * This map will violate the detail of various Map and map view contracts.
++ * As a general rule, don't compare this map to other maps.
++ * <p/>
++ * This {@link java.util.Map} implementation does <i>not</i> allow null elements.
++ * Attempting to add a null key or value to the map will raise a <code>NullPointerException</code>.
++ * <p/>
++ * This implementation is not synchronized.
++ * You can use {@link java.util.Collections#synchronizedMap} to
++ * provide synchronized access to a <code>ReferenceIdentityMap</code>.
++ * Remember that synchronization will not stop the garbage collecter removing entries.
++ * <p/>
++ * All the available iterators can be reset back to the start by casting to
++ * <code>ResettableIterator</code> and calling <code>reset()</code>.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @see java.lang.ref.Reference
++ * @since Commons Collections 3.0 (previously in main package v2.1)
++ */
++public class ReferenceIdentityMap <K,V> extends AbstractReferenceMap<K, V> implements Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -1266190134568365852L;
++
++    /**
++     * Constructs a new <code>ReferenceIdentityMap</code> that will
++     * use hard references to keys and soft references to values.
++     */
++    public ReferenceIdentityMap() {
++        super(HARD, SOFT, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, false);
++    }
++
++    /**
++     * Constructs a new <code>ReferenceIdentityMap</code> that will
++     * use the specified types of references.
++     *
++     * @param keyType   the type of reference to use for keys;
++     *                  must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param valueType the type of reference to use for values;
++     *                  must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     */
++    public ReferenceIdentityMap(int keyType, int valueType) {
++        super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, false);
++    }
++
++    /**
++     * Constructs a new <code>ReferenceIdentityMap</code> that will
++     * use the specified types of references.
++     *
++     * @param keyType     the type of reference to use for keys;
++     *                    must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param valueType   the type of reference to use for values;
++     *                    must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param purgeValues should the value be automatically purged when the
++     *                    key is garbage collected
++     */
++    public ReferenceIdentityMap(int keyType, int valueType, boolean purgeValues) {
++        super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, purgeValues);
++    }
++
++    /**
++     * Constructs a new <code>ReferenceIdentityMap</code> with the
++     * specified reference types, load factor and initial capacity.
++     *
++     * @param keyType    the type of reference to use for keys;
++     *                   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param valueType  the type of reference to use for values;
++     *                   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param capacity   the initial capacity for the map
++     * @param loadFactor the load factor for the map
++     */
++    public ReferenceIdentityMap(int keyType, int valueType, int capacity, float loadFactor) {
++        super(keyType, valueType, capacity, loadFactor, false);
++    }
++
++    /**
++     * Constructs a new <code>ReferenceIdentityMap</code> with the
++     * specified reference types, load factor and initial capacity.
++     *
++     * @param keyType     the type of reference to use for keys;
++     *                    must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param valueType   the type of reference to use for values;
++     *                    must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param capacity    the initial capacity for the map
++     * @param loadFactor  the load factor for the map
++     * @param purgeValues should the value be automatically purged when the
++     *                    key is garbage collected
++     */
++    public ReferenceIdentityMap(int keyType, int valueType, int capacity, float loadFactor, boolean purgeValues) {
++        super(keyType, valueType, capacity, loadFactor, purgeValues);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the hash code for the key specified.
++     * <p/>
++     * This implementation uses the identity hash code.
++     *
++     * @param key the key to get a hash code for
++     * @return the hash code
++     */
++    protected int hash(Object key) {
++        return System.identityHashCode(key);
++    }
++
++    /**
++     * Gets the hash code for a MapEntry.
++     * <p/>
++     * This implementation uses the identity hash code.
++     *
++     * @param key   the key to get a hash code for, may be null
++     * @param value the value to get a hash code for, may be null
++     * @return the hash code, as per the MapEntry specification
++     */
++    protected int hashEntry(Object key, Object value) {
++        return System.identityHashCode(key) ^ System.identityHashCode(value);
++    }
++
++    /**
++     * Compares two keys for equals.
++     * <p/>
++     * This implementation converts the key from the entry to a real reference
++     * before comparison and uses <code>==</code>.
++     *
++     * @param key1 the first key to compare passed in from outside
++     * @param key2 the second key extracted from the entry via <code>entry.key</code>
++     * @return true if equal by identity
++     */
++    protected boolean isEqualKey(Object key1, Object key2) {
++        // GenericsNote: I am disabled this line because of the new way that reference maps work, the getKey() method dereferences them for us.
++        //key2 = (keyType > HARD ? ((Reference) key2).get() : key2);
++        return (key1 == key2);
++    }
++
++    /**
++     * Compares two values for equals.
++     * <p/>
++     * This implementation uses <code>==</code>.
++     *
++     * @param value1 the first value to compare passed in from outside
++     * @param value2 the second value extracted from the entry via <code>getValue()</code>
++     * @return true if equal by identity
++     */
++    protected boolean isEqualValue(Object value1, Object value2) {
++        return (value1 == value2);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        doWriteObject(out);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        doReadObject(in);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/ReferenceMap.java
+@@ -0,0 +1,162 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++
++/**
++ * A <code>Map</code> implementation that allows mappings to be
++ * removed by the garbage collector.
++ * <p/>
++ * When you construct a <code>ReferenceMap</code>, you can specify what kind
++ * of references are used to store the map's keys and values.
++ * If non-hard references are used, then the garbage collector can remove
++ * mappings if a key or value becomes unreachable, or if the JVM's memory is
++ * running low. For information on how the different reference types behave,
++ * see {@link java.lang.ref.Reference}.
++ * <p/>
++ * Different types of references can be specified for keys and values.
++ * The keys can be configured to be weak but the values hard,
++ * in which case this class will behave like a
++ * <a href="http://java.sun.com/j2se/1.4/docs/api/java/util/WeakHashMap.html">
++ * <code>WeakHashMap</code></a>. However, you can also specify hard keys and
++ * weak values, or any other combination. The default constructor uses
++ * hard keys and soft values, providing a memory-sensitive cache.
++ * <p/>
++ * This map is similar to
++ * {@link org.apache.commons.collections15.map.ReferenceIdentityMap ReferenceIdentityMap}.
++ * It differs in that keys and values in this class are compared using <code>equals()</code>.
++ * <p/>
++ * This {@link java.util.Map} implementation does <i>not</i> allow null elements.
++ * Attempting to add a null key or value to the map will raise a <code>NullPointerException</code>.
++ * <p/>
++ * This implementation is not synchronized.
++ * You can use {@link java.util.Collections#synchronizedMap} to
++ * provide synchronized access to a <code>ReferenceMap</code>.
++ * Remember that synchronization will not stop the garbage collecter removing entries.
++ * <p/>
++ * All the available iterators can be reset back to the start by casting to
++ * <code>ResettableIterator</code> and calling <code>reset()</code>.
++ * <p/>
++ * NOTE: As from Commons Collections 3.1 this map extends <code>AbstractReferenceMap</code>
++ * (previously it extended AbstractMap). As a result, the implementation is now
++ * extensible and provides a <code>MapIterator</code>.
++ *
++ * @author Paul Jack
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @see java.lang.ref.Reference
++ * @since Commons Collections 3.0 (previously in main package v2.1)
++ */
++public class ReferenceMap <K,V> extends AbstractReferenceMap<K, V> implements Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 1555089888138299607L;
++
++    /**
++     * Constructs a new <code>ReferenceMap</code> that will
++     * use hard references to keys and soft references to values.
++     */
++    public ReferenceMap() {
++        super(HARD, SOFT, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, false);
++    }
++
++    /**
++     * Constructs a new <code>ReferenceMap</code> that will
++     * use the specified types of references.
++     *
++     * @param keyType   the type of reference to use for keys;
++     *                  must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param valueType the type of reference to use for values;
++     *                  must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     */
++    public ReferenceMap(int keyType, int valueType) {
++        super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, false);
++    }
++
++    /**
++     * Constructs a new <code>ReferenceMap</code> that will
++     * use the specified types of references.
++     *
++     * @param keyType     the type of reference to use for keys;
++     *                    must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param valueType   the type of reference to use for values;
++     *                    must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param purgeValues should the value be automatically purged when the
++     *                    key is garbage collected
++     */
++    public ReferenceMap(int keyType, int valueType, boolean purgeValues) {
++        super(keyType, valueType, DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR, purgeValues);
++    }
++
++    /**
++     * Constructs a new <code>ReferenceMap</code> with the
++     * specified reference types, load factor and initial
++     * capacity.
++     *
++     * @param keyType    the type of reference to use for keys;
++     *                   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param valueType  the type of reference to use for values;
++     *                   must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param capacity   the initial capacity for the map
++     * @param loadFactor the load factor for the map
++     */
++    public ReferenceMap(int keyType, int valueType, int capacity, float loadFactor) {
++        super(keyType, valueType, capacity, loadFactor, false);
++    }
++
++    /**
++     * Constructs a new <code>ReferenceMap</code> with the
++     * specified reference types, load factor and initial
++     * capacity.
++     *
++     * @param keyType     the type of reference to use for keys;
++     *                    must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param valueType   the type of reference to use for values;
++     *                    must be {@link #HARD}, {@link #SOFT}, {@link #WEAK}
++     * @param capacity    the initial capacity for the map
++     * @param loadFactor  the load factor for the map
++     * @param purgeValues should the value be automatically purged when the
++     *                    key is garbage collected
++     */
++    public ReferenceMap(int keyType, int valueType, int capacity, float loadFactor, boolean purgeValues) {
++        super(keyType, valueType, capacity, loadFactor, purgeValues);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        doWriteObject(out);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        doReadObject(in);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/SingletonMap.java
+@@ -0,0 +1,583 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.*;
++import org.apache.commons.collections15.iterators.SingletonIterator;
++import org.apache.commons.collections15.keyvalue.TiedMapEntry;
++
++import java.io.Serializable;
++import java.util.*;
++
++/**
++ * A <code>Map</code> implementation that holds a single item and is fixed size.
++ * <p/>
++ * The single key/value pair is specified at creation.
++ * The map is fixed size so any action that would change the size is disallowed.
++ * However, the <code>put</code> or <code>setValue</code> methods can <i>change</i>
++ * the value associated with the key.
++ * <p/>
++ * If trying to remove or clear the map, an UnsupportedOperationException is thrown.
++ * If trying to put a new mapping into the map, an  IllegalArgumentException is thrown.
++ * The put method will only suceed if the key specified is the same as the
++ * singleton key.
++ * <p/>
++ * The key and value can be obtained by:
++ * <ul>
++ * <li>normal Map methods and views
++ * <li>the <code>MapIterator</code>, see {@link #mapIterator()}
++ * <li>the <code>KeyValue</code> interface (just cast - no object creation)
++ * </ul>
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.1
++ */
++public class SingletonMap <K,V> implements OrderedMap<K, V>, BoundedMap<K, V>, KeyValue<K, V>, Serializable, Cloneable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -8931271118676803261L;
++
++    /**
++     * Singleton key
++     */
++    private final K key;
++    /**
++     * Singleton value
++     */
++    private V value;
++
++    /**
++     * Constructor that creates a map of <code>null</code> to <code>null</code>.
++     */
++    public SingletonMap() {
++        super();
++        this.key = null;
++    }
++
++    /**
++     * Constructor specifying the key and value.
++     *
++     * @param key   the key to use
++     * @param value the value to use
++     */
++    public SingletonMap(K key, V value) {
++        super();
++        this.key = key;
++        this.value = value;
++    }
++
++    /**
++     * Constructor specifying the key and value as a <code>KeyValue</code>.
++     *
++     * @param keyValue the key value pair to use
++     */
++    public SingletonMap(KeyValue<K, V> keyValue) {
++        super();
++        this.key = keyValue.getKey();
++        this.value = keyValue.getValue();
++    }
++
++    /**
++     * Constructor specifying the key and value as a <code>MapEntry</code>.
++     *
++     * @param entry the key value pair to use
++     */
++    public SingletonMap(Map.Entry<K, V> entry) {
++        super();
++        this.key = entry.getKey();
++        this.value = entry.getValue();
++    }
++
++    /**
++     * Constructor copying elements from another map.
++     *
++     * @param map the map to copy, must be size 1
++     * @throws NullPointerException     if the map is null
++     * @throws IllegalArgumentException if the size is not 1
++     */
++    public SingletonMap(Map<? extends K, ? extends V> map) {
++        super();
++        if (map.size() != 1) {
++            throw new IllegalArgumentException("The map size must be 1");
++        }
++        Map.Entry<? extends K, ? extends V> entry = map.entrySet().iterator().next();
++        this.key = entry.getKey();
++        this.value = entry.getValue();
++    }
++
++    // KeyValue
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the key.
++     *
++     * @return the key
++     */
++    public K getKey() {
++        return key;
++    }
++
++    /**
++     * Gets the value.
++     *
++     * @return the value
++     */
++    public V getValue() {
++        return value;
++    }
++
++    /**
++     * Sets the value.
++     *
++     * @param value the new value to set
++     * @return the old value
++     */
++    public V setValue(V value) {
++        V old = this.value;
++        this.value = value;
++        return old;
++    }
++
++    // BoundedMap
++    //-----------------------------------------------------------------------
++    /**
++     * Is the map currently full, always true.
++     *
++     * @return true always
++     */
++    public boolean isFull() {
++        return true;
++    }
++
++    /**
++     * Gets the maximum size of the map, always 1.
++     *
++     * @return 1 always
++     */
++    public int maxSize() {
++        return 1;
++    }
++
++    // Map
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the value mapped to the key specified.
++     *
++     * @param key the key
++     * @return the mapped value, null if no match
++     */
++    public V get(Object key) {
++        if (isEqualKey(key)) {
++            return value;
++        }
++        return null;
++    }
++
++    /**
++     * Gets the size of the map, always 1.
++     *
++     * @return the size of 1
++     */
++    public int size() {
++        return 1;
++    }
++
++    /**
++     * Checks whether the map is currently empty, which it never is.
++     *
++     * @return false always
++     */
++    public boolean isEmpty() {
++        return false;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Checks whether the map contains the specified key.
++     *
++     * @param key the key to search for
++     * @return true if the map contains the key
++     */
++    public boolean containsKey(Object key) {
++        return (isEqualKey(key));
++    }
++
++    /**
++     * Checks whether the map contains the specified value.
++     *
++     * @param value the value to search for
++     * @return true if the map contains the key
++     */
++    public boolean containsValue(Object value) {
++        return (isEqualValue(value));
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Puts a key-value mapping into this map where the key must match the existing key.
++     * <p/>
++     * An IllegalArgumentException is thrown if the key does not match as the map
++     * is fixed size.
++     *
++     * @param key   the key to set, must be the key of the map
++     * @param value the value to set
++     * @return the value previously mapped to this key, null if none
++     * @throws IllegalArgumentException if the key does not match
++     */
++    public V put(K key, V value) {
++        if (isEqualKey(key)) {
++            return setValue(value);
++        }
++        throw new IllegalArgumentException("Cannot put new key/value pair - Map is fixed size singleton");
++    }
++
++    /**
++     * Puts the values from the specified map into this map.
++     * <p/>
++     * The map must be of size 0 or size 1.
++     * If it is size 1, the key must match the key of this map otherwise an
++     * IllegalArgumentException is thrown.
++     *
++     * @param map the map to add, must be size 0 or 1, and the key must match
++     * @throws NullPointerException     if the map is null
++     * @throws IllegalArgumentException if the key does not match
++     */
++    public void putAll(Map<? extends K, ? extends V> map) {
++        switch (map.size()) {
++            case 0:
++                return;
++
++            case 1:
++                Map.Entry<? extends K, ? extends V> entry = map.entrySet().iterator().next();
++                put(entry.getKey(), entry.getValue());
++                return;
++
++            default:
++                throw new IllegalArgumentException("The map size must be 0 or 1");
++        }
++    }
++
++    /**
++     * Unsupported operation.
++     *
++     * @param key the mapping to remove
++     * @return the value mapped to the removed key, null if key not in map
++     * @throws UnsupportedOperationException always
++     */
++    public V remove(Object key) {
++        throw new UnsupportedOperationException();
++    }
++
++    /**
++     * Unsupported operation.
++     */
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the entrySet view of the map.
++     * Changes made via <code>setValue</code> affect this map.
++     * To simply iterate through the entries, use {@link #mapIterator()}.
++     *
++     * @return the entrySet view
++     */
++    public Set<Map.Entry<K, V>> entrySet() {
++        Map.Entry<K, V> entry = new TiedMapEntry<K, V>(this, getKey());
++        return Collections.singleton(entry);
++    }
++
++    /**
++     * Gets the unmodifiable keySet view of the map.
++     * Changes made to the view affect this map.
++     * To simply iterate through the keys, use {@link #mapIterator()}.
++     *
++     * @return the keySet view
++     */
++    public Set<K> keySet() {
++        return Collections.singleton(key);
++    }
++
++    /**
++     * Gets the unmodifiable values view of the map.
++     * Changes made to the view affect this map.
++     * To simply iterate through the values, use {@link #mapIterator()}.
++     *
++     * @return the values view
++     */
++    public Collection<V> values() {
++        return new SingletonValues(this);
++    }
++
++    /**
++     * Gets an iterator over the map.
++     * Changes made to the iterator using <code>setValue</code> affect this map.
++     * The <code>remove</code> method is unsupported.
++     * <p/>
++     * A MapIterator returns the keys in the map. It also provides convenient
++     * methods to get the key and value, and set the value.
++     * It avoids the need to create an entrySet/keySet/values object.
++     * It also avoids creating the Map Entry object.
++     *
++     * @return the map iterator
++     */
++    public MapIterator<K, V> mapIterator() {
++        return new SingletonMapIterator<K, V>(this);
++    }
++
++    // OrderedMap
++    //-----------------------------------------------------------------------
++    /**
++     * Obtains an <code>OrderedMapIterator</code> over the map.
++     * <p/>
++     * A ordered map iterator is an efficient way of iterating over maps
++     * in both directions.
++     *
++     * @return an ordered map iterator
++     */
++    public OrderedMapIterator<K, V> orderedMapIterator() {
++        return new SingletonMapIterator<K, V>(this);
++    }
++
++    /**
++     * Gets the first (and only) key in the map.
++     *
++     * @return the key
++     */
++    public K firstKey() {
++        return getKey();
++    }
++
++    /**
++     * Gets the last (and only) key in the map.
++     *
++     * @return the key
++     */
++    public K lastKey() {
++        return getKey();
++    }
++
++    /**
++     * Gets the next key after the key specified, always null.
++     *
++     * @param key the next key
++     * @return null always
++     */
++    public K nextKey(K key) {
++        return null;
++    }
++
++    /**
++     * Gets the previous key before the key specified, always null.
++     *
++     * @param key the next key
++     * @return null always
++     */
++    public K previousKey(K key) {
++        return null;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Compares the specified key to the stored key.
++     *
++     * @param key the key to compare
++     * @return true if equal
++     */
++    protected boolean isEqualKey(Object key) {
++        return (key == null ? getKey() == null : key.equals(getKey()));
++    }
++
++    /**
++     * Compares the specified value to the stored value.
++     *
++     * @param value the value to compare
++     * @return true if equal
++     */
++    protected boolean isEqualValue(Object value) {
++        return (value == null ? getValue() == null : value.equals(getValue()));
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * SingletonMapIterator.
++     */
++    static class SingletonMapIterator <K,V> implements OrderedMapIterator<K, V>, ResettableIterator<K> {
++        private final SingletonMap<K, V> parent;
++        private boolean hasNext = true;
++        private boolean canGetSet = false;
++
++        SingletonMapIterator(SingletonMap<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public boolean hasNext() {
++            return hasNext;
++        }
++
++        public K next() {
++            if (hasNext == false) {
++                throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
++            }
++            hasNext = false;
++            canGetSet = true;
++            return parent.getKey();
++        }
++
++        public boolean hasPrevious() {
++            return (hasNext == false);
++        }
++
++        public K previous() {
++            if (hasNext == true) {
++                throw new NoSuchElementException(AbstractHashedMap.NO_PREVIOUS_ENTRY);
++            }
++            hasNext = true;
++            return parent.getKey();
++        }
++
++        public void remove() {
++            throw new UnsupportedOperationException();
++        }
++
++        public K getKey() {
++            if (canGetSet == false) {
++                throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
++            }
++            return parent.getKey();
++        }
++
++        public V getValue() {
++            if (canGetSet == false) {
++                throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
++            }
++            return parent.getValue();
++        }
++
++        public V setValue(V value) {
++            if (canGetSet == false) {
++                throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
++            }
++            return parent.setValue(value);
++        }
++
++        public void reset() {
++            hasNext = true;
++        }
++
++        public String toString() {
++            if (hasNext) {
++                return "Iterator[]";
++            } else {
++                return "Iterator[" + getKey() + "=" + getValue() + "]";
++            }
++        }
++    }
++
++    /**
++     * Values implementation for the SingletonMap.
++     * This class is needed as values is a view that must update as the map updates.
++     */
++    static class SingletonValues <K,V> extends AbstractSet<V> implements Serializable {
++        private static final long serialVersionUID = -3689524741863047872L;
++        private final SingletonMap<K, V> parent;
++
++        SingletonValues(SingletonMap<K, V> parent) {
++            super();
++            this.parent = parent;
++        }
++
++        public int size() {
++            return 1;
++        }
++
++        public boolean isEmpty() {
++            return false;
++        }
++
++        public boolean contains(Object object) {
++            return parent.containsValue(object);
++        }
++
++        public void clear() {
++            throw new UnsupportedOperationException();
++        }
++
++        public Iterator<V> iterator() {
++            return new SingletonIterator<V>(parent.getValue(), false);
++        }
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Clones the map without cloning the key or value.
++     *
++     * @return a shallow clone
++     */
++    public Object clone() {
++        try {
++            SingletonMap cloned = (SingletonMap) super.clone();
++            return cloned;
++        } catch (CloneNotSupportedException ex) {
++            throw new InternalError();
++        }
++    }
++
++    /**
++     * Compares this map with another.
++     *
++     * @param obj the object to compare to
++     * @return true if equal
++     */
++    public boolean equals(Object obj) {
++        if (obj == this) {
++            return true;
++        }
++        if (obj instanceof Map == false) {
++            return false;
++        }
++        Map other = (Map) obj;
++        if (other.size() != 1) {
++            return false;
++        }
++        Map.Entry entry = (Map.Entry) other.entrySet().iterator().next();
++        return isEqualKey(entry.getKey()) && isEqualValue(entry.getValue());
++    }
++
++    /**
++     * Gets the standard Map hashCode.
++     *
++     * @return the hash code defined in the Map interface
++     */
++    public int hashCode() {
++        return (getKey() == null ? 0 : getKey().hashCode()) ^ (getValue() == null ? 0 : getValue().hashCode());
++    }
++
++    /**
++     * Gets the map as a String.
++     *
++     * @return a string version of the map
++     */
++    public String toString() {
++        return new StringBuffer(128).append('{').append(getKey()).append('=').append(getValue()).append('}').toString();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/StaticBucketMap.java
+@@ -0,0 +1,702 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2002-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.KeyValue;
++
++import java.util.*;
++
++/**
++ * A StaticBucketMap is an efficient, thread-safe implementation of
++ * <code>java.util.Map</code> that performs well in in a highly
++ * thread-contentious environment.  The map supports very efficient
++ * {@link #get(Object) get}, {@link #put(Object,Object) put},
++ * {@link #remove(Object) remove} and {@link #containsKey(Object) containsKey}
++ * operations, assuming (approximate) uniform hashing and
++ * that the number of entries does not exceed the number of buckets.  If the
++ * number of entries exceeds the number of buckets or if the hash codes of the
++ * objects are not uniformly distributed, these operations have a worst case
++ * scenario that is proportional to the number of elements in the map
++ * (<i>O(n)</i>).<p>
++ * <p/>
++ * Each bucket in the hash table has its own monitor, so two threads can
++ * safely operate on the map at the same time, often without incurring any
++ * monitor contention.  This means that you don't have to wrap instances
++ * of this class with {@link java.util.Collections#synchronizedMap(Map)};
++ * instances are already thread-safe.  Unfortunately, however, this means
++ * that this map implementation behaves in ways you may find disconcerting.
++ * Bulk operations, such as {@link #putAll(Map) putAll} or the
++ * {@link Collection#retainAll(Collection) retainAll} operation in collection
++ * views, are <i>not</i> atomic.  If two threads are simultaneously
++ * executing
++ * <p/>
++ * <pre>
++ *   staticBucketMapInstance.putAll(map);
++ * </pre>
++ * <p/>
++ * and
++ * <p/>
++ * <pre>
++ *   staticBucketMapInstance.entrySet().removeAll(map.entrySet());
++ * </pre>
++ * <p/>
++ * then the results are generally random.  Those two statement could cancel
++ * each other out, leaving <code>staticBucketMapInstance</code> essentially
++ * unchanged, or they could leave some random subset of <code>map</code> in
++ * <code>staticBucketMapInstance</code>.<p>
++ * <p/>
++ * Also, much like an encyclopedia, the results of {@link #size()} and
++ * {@link #isEmpty()} are out-of-date as soon as they are produced.<p>
++ * <p/>
++ * The iterators returned by the collection views of this class are <i>not</i>
++ * fail-fast.  They will <i>never</i> raise a
++ * {@link java.util.ConcurrentModificationException}.  Keys and values
++ * added to the map after the iterator is created do not necessarily appear
++ * during iteration.  Similarly, the iterator does not necessarily fail to
++ * return keys and values that were removed after the iterator was created.<p>
++ * <p/>
++ * Finally, unlike {@link java.util.HashMap}-style implementations, this
++ * class <i>never</i> rehashes the map.  The number of buckets is fixed
++ * at construction time and never altered.  Performance may degrade if
++ * you do not allocate enough buckets upfront.<p>
++ * <p/>
++ * The {@link #atomic(Runnable)} method is provided to allow atomic iterations
++ * and bulk operations; however, overuse of {@link #atomic(Runnable) atomic}
++ * will basically result in a map that's slower than an ordinary synchronized
++ * {@link java.util.HashMap}.
++ * <p/>
++ * Use this class if you do not require reliable bulk operations and
++ * iterations, or if you can make your own guarantees about how bulk
++ * operations will affect the map.<p>
++ *
++ * @author Berin Loritsch
++ * @author Gerhard Froehlich
++ * @author Michael A. Smith
++ * @author Paul Jack
++ * @author Leo Sutic
++ * @author Matt Hall, John Watkinson, Janek Bogucki
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0 (previously in main package v2.1)
++ */
++public final class StaticBucketMap <K,V> implements Map<K, V> {
++
++    /**
++     * The default number of buckets to use
++     */
++    private static final int DEFAULT_BUCKETS = 255;
++    /**
++     * The array of buckets, where the actual data is held
++     */
++    private Node<K, V>[] buckets;
++    /**
++     * The matching array of locks
++     */
++    private Lock[] locks;
++
++    /**
++     * Initializes the map with the default number of buckets (255).
++     */
++    public StaticBucketMap() {
++        this(DEFAULT_BUCKETS);
++    }
++
++    /**
++     * Initializes the map with a specified number of buckets.  The number
++     * of buckets is never below 17, and is always an odd number (StaticBucketMap
++     * ensures this). The number of buckets is inversely proportional to the
++     * chances for thread contention.  The fewer buckets, the more chances for
++     * thread contention.  The more buckets the fewer chances for thread
++     * contention.
++     *
++     * @param numBuckets the number of buckets for this map
++     */
++    public StaticBucketMap(int numBuckets) {
++        int size = Math.max(17, numBuckets);
++
++        // Ensure that bucketSize is never a power of 2 (to ensure maximal distribution)
++        if (size % 2 == 0) {
++            size--;
++        }
++
++        buckets = new Node[size];
++        locks = new Lock[size];
++
++        for (int i = 0; i < size; i++) {
++            locks[i] = new Lock();
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Determine the exact hash entry for the key.  The hash algorithm
++     * is rather simplistic, but it does the job:
++     * <p/>
++     * <pre>
++     *   He = |Hk mod n|
++     * </pre>
++     * <p/>
++     * <p/>
++     * He is the entry's hashCode, Hk is the key's hashCode, and n is
++     * the number of buckets.
++     * </p>
++     */
++    private final int getHash(Object key) {
++        if (key == null) {
++            return 0;
++        }
++        int hash = key.hashCode();
++        hash += ~(hash << 15);
++        hash ^= (hash >>> 10);
++        hash += (hash << 3);
++        hash ^= (hash >>> 6);
++        hash += ~(hash << 11);
++        hash ^= (hash >>> 16);
++        hash %= buckets.length;
++        return (hash < 0) ? hash * -1 : hash;
++    }
++
++    /**
++     * Gets the current size of the map.
++     * The value is computed fresh each time the method is called.
++     *
++     * @return the current size
++     */
++    public int size() {
++        int cnt = 0;
++
++        for (int i = 0; i < buckets.length; i++) {
++            cnt += locks[i].size;
++        }
++        return cnt;
++    }
++
++    /**
++     * Checks if the size is currently zero.
++     *
++     * @return true if empty
++     */
++    public boolean isEmpty() {
++        return (size() == 0);
++    }
++
++    /**
++     * Gets the value associated with the key.
++     *
++     * @param key the key to retrieve
++     * @return the associated value
++     */
++    public V get(final Object key) {
++        int hash = getHash(key);
++
++        synchronized (locks[hash]) {
++            Node<K, V> n = buckets[hash];
++
++            while (n != null) {
++                if (n.key == key || (n.key != null && n.key.equals(key))) {
++                    return n.value;
++                }
++
++                n = n.next;
++            }
++        }
++        return null;
++    }
++
++    /**
++     * Checks if the map contains the specified key.
++     *
++     * @param key the key to check
++     * @return true if found
++     */
++    public boolean containsKey(final Object key) {
++        int hash = getHash(key);
++
++        synchronized (locks[hash]) {
++            Node n = buckets[hash];
++
++            while (n != null) {
++                if (n.key == null || (n.key != null && n.key.equals(key))) {
++                    return true;
++                }
++
++                n = n.next;
++            }
++        }
++        return false;
++    }
++
++    /**
++     * Checks if the map contains the specified value.
++     *
++     * @param value the value to check
++     * @return true if found
++     */
++    public boolean containsValue(final Object value) {
++        for (int i = 0; i < buckets.length; i++) {
++            synchronized (locks[i]) {
++                Node n = buckets[i];
++
++                while (n != null) {
++                    if (n.value == value || (n.value != null && n.value.equals(value))) {
++                        return true;
++                    }
++
++                    n = n.next;
++                }
++            }
++        }
++        return false;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Puts a new key value mapping into the map.
++     *
++     * @param key   the key to use
++     * @param value the value to use
++     * @return the previous mapping for the key
++     */
++    public V put(final K key, final V value) {
++        int hash = getHash(key);
++
++        synchronized (locks[hash]) {
++            Node<K, V> n = buckets[hash];
++
++            if (n == null) {
++                n = new Node<K, V>();
++                n.key = key;
++                n.value = value;
++                buckets[hash] = n;
++                locks[hash].size++;
++                return null;
++            }
++
++            // Set n to the last node in the linked list.  Check each key along the way
++            //  If the key is found, then change the value of that node and return
++            //  the old value.
++            for (Node<K, V> next = n; next != null; next = next.next) {
++                n = next;
++
++                if (n.key == key || (n.key != null && n.key.equals(key))) {
++                    V returnVal = n.value;
++                    n.value = value;
++                    return returnVal;
++                }
++            }
++
++            // The key was not found in the current list of nodes, add it to the end
++            //  in a new node.
++            Node<K, V> newNode = new Node<K, V>();
++            newNode.key = key;
++            newNode.value = value;
++            n.next = newNode;
++            locks[hash].size++;
++        }
++        return null;
++    }
++
++    /**
++     * Removes the specified key from the map.
++     *
++     * @param key the key to remove
++     * @return the previous value at this key
++     */
++    public V remove(Object key) {
++        int hash = getHash(key);
++
++        synchronized (locks[hash]) {
++            Node<K, V> n = buckets[hash];
++            Node<K, V> prev = null;
++
++            while (n != null) {
++                if (n.key == key || (n.key != null && n.key.equals(key))) {
++                    // Remove this node from the linked list of nodes.
++                    if (null == prev) {
++                        // This node was the head, set the next node to be the new head.
++                        buckets[hash] = n.next;
++                    } else {
++                        // Set the next node of the previous node to be the node after this one.
++                        prev.next = n.next;
++                    }
++                    locks[hash].size--;
++                    return n.value;
++                }
++
++                prev = n;
++                n = n.next;
++            }
++        }
++        return null;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the key set.
++     *
++     * @return the key set
++     */
++    public Set<K> keySet() {
++        return new KeySet();
++    }
++
++    /**
++     * Gets the values.
++     *
++     * @return the values
++     */
++    public Collection<V> values() {
++        return new Values();
++    }
++
++    /**
++     * Gets the entry set.
++     *
++     * @return the entry set
++     */
++    public Set<Map.Entry<K, V>> entrySet() {
++        return new EntrySet();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Puts all the entries from the specified map into this map.
++     * This operation is <b>not atomic</b> and may have undesired effects.
++     *
++     * @param map the map of entries to add
++     */
++    public void putAll(Map<? extends K, ? extends V> map) {
++        Iterator i = map.keySet().iterator();
++
++        while (i.hasNext()) {
++            K key = (K) i.next();
++            put(key, (V) map.get(key));
++        }
++    }
++
++    /**
++     * Clears the map of all entries.
++     */
++    public void clear() {
++        for (int i = 0; i < buckets.length; i++) {
++            Lock lock = locks[i];
++            synchronized (lock) {
++                buckets[i] = null;
++                lock.size = 0;
++            }
++        }
++    }
++
++    /**
++     * Compares this map to another, as per the Map specification.
++     *
++     * @param obj the object to compare to
++     * @return true if equal
++     */
++    public boolean equals(Object obj) {
++        if (obj == this) {
++            return true;
++        }
++        if (obj instanceof Map == false) {
++            return false;
++        }
++        Map other = (Map) obj;
++        return entrySet().equals(other.entrySet());
++    }
++
++    /**
++     * Gets the hash code, as per the Map specification.
++     *
++     * @return the hash code
++     */
++    public int hashCode() {
++        int hashCode = 0;
++
++        for (int i = 0; i < buckets.length; i++) {
++            synchronized (locks[i]) {
++                Node n = buckets[i];
++
++                while (n != null) {
++                    hashCode += n.hashCode();
++                    n = n.next;
++                }
++            }
++        }
++        return hashCode;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * The Map.Entry for the StaticBucketMap.
++     */
++    private static final class Node <K,V> implements Map.Entry<K, V>, KeyValue<K, V> {
++        protected K key;
++        protected V value;
++        protected Node<K, V> next;
++
++        public K getKey() {
++            return key;
++        }
++
++        public V getValue() {
++            return value;
++        }
++
++        public int hashCode() {
++            return ((key == null ? 0 : key.hashCode()) ^ (value == null ? 0 : value.hashCode()));
++        }
++
++        public boolean equals(Object obj) {
++            if (obj == this) {
++                return true;
++            }
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++
++            Map.Entry e2 = (Map.Entry) obj;
++            return ((key == null ? e2.getKey() == null : key.equals(e2.getKey())) && (value == null ? e2.getValue() == null : value.equals(e2.getValue())));
++        }
++
++        public V setValue(V obj) {
++            V retVal = value;
++            value = obj;
++            return retVal;
++        }
++    }
++
++
++    /**
++     * The lock object, which also includes a count of the nodes in this lock.
++     */
++    private final static class Lock {
++        public int size;
++    }
++
++    private class EntryIterator extends IteratorBase implements Iterator<Map.Entry<K, V>> {
++
++        public Entry<K, V> next() {
++            return superNext();
++        }
++
++    }
++
++    //-----------------------------------------------------------------------
++    private class IteratorBase {
++
++        private ArrayList<Map.Entry<K, V>> current = new ArrayList<Map.Entry<K, V>>();
++        private int bucket;
++        private Map.Entry<K, V> last;
++
++
++        public boolean hasNext() {
++            if (current.size() > 0) return true;
++            while (bucket < buckets.length) {
++                synchronized (locks[bucket]) {
++                    Node<K, V> n = buckets[bucket];
++                    while (n != null) {
++                        current.add(n);
++                        n = n.next;
++                    }
++                    bucket++;
++                    if (current.size() > 0) return true;
++                }
++            }
++            return false;
++        }
++
++        protected Map.Entry<K, V> nextEntry() {
++            if (!hasNext()) throw new NoSuchElementException();
++            last = current.remove(current.size() - 1);
++            return last;
++        }
++
++        public Map.Entry<K, V> superNext() {
++            return nextEntry();
++        }
++
++        public void remove() {
++            if (last == null) throw new IllegalStateException();
++            StaticBucketMap.this.remove(last.getKey());
++            last = null;
++        }
++
++    }
++
++    private class ValueIterator extends IteratorBase implements Iterator<V> {
++
++        public V next() {
++            return nextEntry().getValue();
++        }
++
++    }
++
++    private class KeyIterator extends IteratorBase implements Iterator<K> {
++
++        public K next() {
++            return nextEntry().getKey();
++        }
++
++    }
++
++    private class EntrySet extends AbstractSet<Map.Entry<K, V>> {
++
++        public int size() {
++            return StaticBucketMap.this.size();
++        }
++
++        public void clear() {
++            StaticBucketMap.this.clear();
++        }
++
++        public Iterator<Map.Entry<K, V>> iterator() {
++            return new EntryIterator();
++        }
++
++        public boolean contains(Object obj) {
++            Map.Entry entry = (Map.Entry) obj;
++            int hash = getHash(entry.getKey());
++            synchronized (locks[hash]) {
++                for (Node n = buckets[hash]; n != null; n = n.next) {
++                    if (n.equals(entry)) return true;
++                }
++            }
++            return false;
++        }
++
++        public boolean remove(Object obj) {
++            if (obj instanceof Map.Entry == false) {
++                return false;
++            }
++            Map.Entry entry = (Map.Entry) obj;
++            int hash = getHash(entry.getKey());
++            synchronized (locks[hash]) {
++                for (Node n = buckets[hash]; n != null; n = n.next) {
++                    if (n.equals(entry)) {
++                        StaticBucketMap.this.remove(n.getKey());
++                        return true;
++                    }
++                }
++            }
++            return false;
++        }
++
++    }
++
++
++    private class KeySet extends AbstractSet<K> {
++
++        public int size() {
++            return StaticBucketMap.this.size();
++        }
++
++        public void clear() {
++            StaticBucketMap.this.clear();
++        }
++
++        public Iterator<K> iterator() {
++            return new KeyIterator();
++        }
++
++        public boolean contains(Object obj) {
++            return StaticBucketMap.this.containsKey(obj);
++        }
++
++        public boolean remove(Object obj) {
++            int hash = getHash(obj);
++            synchronized (locks[hash]) {
++                for (Node n = buckets[hash]; n != null; n = n.next) {
++                    Object k = n.getKey();
++                    if ((k == obj) || ((k != null) && k.equals(obj))) {
++                        StaticBucketMap.this.remove(k);
++                        return true;
++                    }
++                }
++            }
++            return false;
++
++        }
++
++    }
++
++
++    private class Values extends AbstractCollection<V> {
++
++        public int size() {
++            return StaticBucketMap.this.size();
++        }
++
++        public void clear() {
++            StaticBucketMap.this.clear();
++        }
++
++        public Iterator<V> iterator() {
++            return new ValueIterator();
++        }
++
++    }
++
++
++    /**
++     * Prevents any operations from occurring on this map while the
++     * given {@link Runnable} executes.  This method can be used, for
++     * instance, to execute a bulk operation atomically:
++     * <p/>
++     * <pre>
++     *    staticBucketMapInstance.atomic(new Runnable() {
++     *        public void run() {
++     *            staticBucketMapInstance.putAll(map);
++     *        }
++     *    });
++     *  </pre>
++     * <p/>
++     * It can also be used if you need a reliable iterator:
++     * <p/>
++     * <pre>
++     *    staticBucketMapInstance.atomic(new Runnable() {
++     *        public void run() {
++     *            Iterator iterator = staticBucketMapInstance.iterator();
++     *            while (iterator.hasNext()) {
++     *                foo(iterator.next();
++     *            }
++     *        }
++     *    });
++     *  </pre>
++     * <p/>
++     * <b>Implementation note:</b> This method requires a lot of time
++     * and a ton of stack space.  Essentially a recursive algorithm is used
++     * to enter each bucket's monitor.  If you have twenty thousand buckets
++     * in your map, then the recursive method will be invoked twenty thousand
++     * times.  You have been warned.
++     *
++     * @param r the code to execute atomically
++     */
++    public void atomic(Runnable r) {
++        if (r == null) throw new NullPointerException();
++        atomic(r, 0);
++    }
++
++    private void atomic(Runnable r, int bucket) {
++        if (bucket >= buckets.length) {
++            r.run();
++            return;
++        }
++        synchronized (locks[bucket]) {
++            atomic(r, bucket + 1);
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/TransformedMap.java
+@@ -0,0 +1,200 @@
++// TODO: Not yet converted, deprecated (by me).
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Iterator;
++import java.util.Map;
++
++/**
++ * Decorates another <code>Map</code> to transform objects that are added.
++ * <p/>
++ * The Map put methods and Map.Entry setValue method are affected by this class.
++ * Thus objects must be removed or searched for using their transformed form.
++ * For example, if the transformation converts Strings to Integers, you must
++ * use the Integer form to remove objects.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ * <p>
++ * Note: This class cannot support generics without breaking the Map contract.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class TransformedMap extends AbstractInputCheckedMapDecorator implements Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 7023152376788900464L;
++
++    /**
++     * The transformer to use for the key
++     */
++    protected final Transformer keyTransformer;
++    /**
++     * The transformer to use for the value
++     */
++    protected final Transformer valueTransformer;
++
++    /**
++     * Factory method to create a transforming map.
++     * <p/>
++     * If there are any elements already in the map being decorated, they
++     * are NOT transformed.
++     *
++     * @param map              the map to decorate, must not be null
++     * @param keyTransformer   the transformer to use for key conversion, null means no conversion
++     * @param valueTransformer the transformer to use for value conversion, null means no conversion
++     * @throws IllegalArgumentException if map is null
++     */
++    public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
++        return new TransformedMap(map, keyTransformer, valueTransformer);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the collection being decorated, they
++     * are NOT transformed.
++     *
++     * @param map              the map to decorate, must not be null
++     * @param keyTransformer   the transformer to use for key conversion, null means no conversion
++     * @param valueTransformer the transformer to use for value conversion, null means no conversion
++     * @throws IllegalArgumentException if map is null
++     */
++    protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
++        super(map);
++        this.keyTransformer = keyTransformer;
++        this.valueTransformer = valueTransformer;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     * @since Commons Collections 3.1
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(map);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     * @since Commons Collections 3.1
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        map = (Map) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Transforms a key.
++     * <p/>
++     * The transformer itself may throw an exception if necessary.
++     *
++     * @param object the object to transform
++     * @throws the transformed object
++     */
++    protected Object transformKey(Object object) {
++        if (keyTransformer == null) {
++            return object;
++        }
++        return keyTransformer.transform(object);
++    }
++
++    /**
++     * Transforms a value.
++     * <p/>
++     * The transformer itself may throw an exception if necessary.
++     *
++     * @param object the object to transform
++     * @throws the transformed object
++     */
++    protected Object transformValue(Object object) {
++        if (valueTransformer == null) {
++            return object;
++        }
++        return valueTransformer.transform(object);
++    }
++
++    /**
++     * Transforms a map.
++     * <p/>
++     * The transformer itself may throw an exception if necessary.
++     *
++     * @param map the map to transform
++     * @throws the transformed object
++     */
++    protected Map transformMap(Map map) {
++        Map result = new LinkedMap(map.size());
++        for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
++            Map.Entry entry = (Map.Entry) it.next();
++            result.put(transformKey(entry.getKey()), transformValue(entry.getValue()));
++        }
++        return result;
++    }
++
++    /**
++     * Override to transform the value when using <code>setValue</code>.
++     *
++     * @param value the value to transform
++     * @return the transformed value
++     * @since Commons Collections 3.1
++     */
++    protected Object checkSetValue(Object value) {
++        return valueTransformer.transform(value);
++    }
++
++    /**
++     * Override to only return true when there is a value transformer.
++     *
++     * @return true if a value transformer is in use
++     * @since Commons Collections 3.1
++     */
++    protected boolean isSetValueChecking() {
++        return (valueTransformer != null);
++    }
++
++    //-----------------------------------------------------------------------
++    public Object put(Object key, Object value) {
++        key = transformKey(key);
++        value = transformValue(value);
++        return getMap().put(key, value);
++    }
++
++    public void putAll(Map mapToCopy) {
++        mapToCopy = transformMap(mapToCopy);
++        getMap().putAll(mapToCopy);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/TransformedSortedMap.java
+@@ -0,0 +1,116 @@
++// TODO: Not yet converted, deprecated (by me).
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.util.Comparator;
++import java.util.SortedMap;
++
++/**
++ * Decorates another <code>SortedMap </code> to transform objects that are added.
++ * <p/>
++ * The Map put methods and Map.Entry setValue method are affected by this class.
++ * Thus objects must be removed or searched for using their transformed form.
++ * For example, if the transformation converts Strings to Integers, you must
++ * use the Integer form to remove objects.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ * <p>
++ * Note: This class cannot support generics without breaking the Map contract.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public class TransformedSortedMap extends TransformedMap implements SortedMap {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -8751771676410385778L;
++
++    /**
++     * Factory method to create a transforming sorted map.
++     * <p/>
++     * If there are any elements already in the map being decorated, they
++     * are NOT transformed.
++     *
++     * @param map              the map to decorate, must not be null
++     * @param keyTransformer   the predicate to validate the keys, null means no transformation
++     * @param valueTransformer the predicate to validate to values, null means no transformation
++     * @throws IllegalArgumentException if the map is null
++     */
++    public static SortedMap decorate(SortedMap map, Transformer keyTransformer, Transformer valueTransformer) {
++        return new TransformedSortedMap(map, keyTransformer, valueTransformer);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the collection being decorated, they
++     * are NOT transformed.</p>
++     *
++     * @param map              the map to decorate, must not be null
++     * @param keyTransformer   the predicate to validate the keys, null means no transformation
++     * @param valueTransformer the predicate to validate to values, null means no transformation
++     * @throws IllegalArgumentException if the map is null
++     */
++    protected TransformedSortedMap(SortedMap map, Transformer keyTransformer, Transformer valueTransformer) {
++        super(map, keyTransformer, valueTransformer);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the map being decorated.
++     *
++     * @return the decorated map
++     */
++    protected SortedMap getSortedMap() {
++        return (SortedMap) map;
++    }
++
++    //-----------------------------------------------------------------------
++    public Object firstKey() {
++        return getSortedMap().firstKey();
++    }
++
++    public Object lastKey() {
++        return getSortedMap().lastKey();
++    }
++
++    public Comparator comparator() {
++        return getSortedMap().comparator();
++    }
++
++    public SortedMap subMap(Object fromKey, Object toKey) {
++        SortedMap map = getSortedMap().subMap(fromKey, toKey);
++        return new TransformedSortedMap(map, keyTransformer, valueTransformer);
++    }
++
++    public SortedMap headMap(Object toKey) {
++        SortedMap map = getSortedMap().headMap(toKey);
++        return new TransformedSortedMap(map, keyTransformer, valueTransformer);
++    }
++
++    public SortedMap tailMap(Object fromKey) {
++        SortedMap map = getSortedMap().tailMap(fromKey);
++        return new TransformedSortedMap(map, keyTransformer, valueTransformer);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/TypedMap.java
+@@ -0,0 +1,63 @@
++// TODO: Not yet converted, deprecated (by me).
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.functors.InstanceofPredicate;
++
++import java.util.Map;
++
++/**
++ * Decorates another <code>Map</code> to validate that elements added
++ * are of a specific type.
++ * <p/>
++ * The validation of additions is performed via an instanceof test against
++ * a specified <code>Class</code>. If an object cannot be added to the
++ * collection, an IllegalArgumentException is thrown.
++ * <p/>
++ * The returned implementation is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ * @deprecated no longer needed with Java generics.
++ */
++public class TypedMap {
++
++    /**
++     * Factory method to create a typed map.
++     * <p/>
++     * If there are any elements already in the map being decorated, they
++     * are validated.
++     *
++     * @param map       the map to decorate, must not be null
++     * @param keyType   the type to allow as keys, must not be null
++     * @param valueType the type to allow as values, must not be null
++     * @throws IllegalArgumentException if list or type is null
++     * @throws IllegalArgumentException if the list contains invalid elements
++     */
++    public static Map decorate(Map map, Class keyType, Class valueType) {
++        return new PredicatedMap(map, InstanceofPredicate.getInstance(keyType), InstanceofPredicate.getInstance(valueType));
++    }
++
++    /**
++     * Restrictive constructor.
++     */
++    protected TypedMap() {
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/TypedSortedMap.java
+@@ -0,0 +1,63 @@
++// TODO: Not yet converted, deprecated (by me).
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.functors.InstanceofPredicate;
++
++import java.util.SortedMap;
++
++/**
++ * Decorates another <code>SortedMap</code> to validate that elements added
++ * are of a specific type.
++ * <p/>
++ * The validation of additions is performed via an instanceof test against
++ * a specified <code>Class</code>. If an object cannot be added to the
++ * collection, an IllegalArgumentException is thrown.
++ * <p/>
++ * The returned implementation is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ * @deprecated no longer needed with Java generics.
++ */
++public class TypedSortedMap {
++
++    /**
++     * Factory method to create a typed sorted map.
++     * <p/>
++     * If there are any elements already in the map being decorated, they
++     * are validated.
++     *
++     * @param map       the map to decorate, must not be null
++     * @param keyType   the type to allow as keys, must not be null
++     * @param valueType the type to allow as values, must not be null
++     * @throws IllegalArgumentException if list or type is null
++     * @throws IllegalArgumentException if the list contains invalid elements
++     */
++    public static SortedMap decorate(SortedMap map, Class keyType, Class valueType) {
++        return new PredicatedSortedMap(map, InstanceofPredicate.getInstance(keyType), InstanceofPredicate.getInstance(valueType));
++    }
++
++    /**
++     * Restrictive constructor.
++     */
++    protected TypedSortedMap() {
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/UnmodifiableEntrySet.java
+@@ -0,0 +1,161 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.iterators.AbstractIteratorDecorator;
++import org.apache.commons.collections15.keyvalue.AbstractMapEntryDecorator;
++import org.apache.commons.collections15.set.AbstractSetDecorator;
++
++import java.lang.reflect.Array;
++import java.util.*;
++
++/**
++ * Decorates a map entry <code>Set</code> to ensure it can't be altered.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableEntrySet <K,V> extends AbstractSetDecorator<Map.Entry<K, V>> implements Unmodifiable {
++
++    /**
++     * Factory method to create an unmodifiable set of Map Entry objects.
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    public static <K,V> Set<Map.Entry<K, V>> decorate(Set<Map.Entry<K, V>> set) {
++        if (set instanceof Unmodifiable) {
++            return set;
++        }
++        return new UnmodifiableEntrySet<K, V>(set);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    private UnmodifiableEntrySet(Set<Map.Entry<K, V>> set) {
++        super(set);
++    }
++
++    //-----------------------------------------------------------------------
++    public boolean add(Map.Entry<K, V> object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean addAll(Collection<? extends Map.Entry<K, V>> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean remove(Object object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    //-----------------------------------------------------------------------
++    public Iterator<Map.Entry<K, V>> iterator() {
++        return new UnmodifiableEntrySetIterator<K, V>(collection.iterator());
++    }
++
++    public Object[] toArray() {
++        Object[] array = collection.toArray();
++        for (int i = 0; i < array.length; i++) {
++            array[i] = new UnmodifiableEntry((Map.Entry) array[i]);
++        }
++        return array;
++    }
++
++    public <T> T[] toArray(T array[]) {
++        T[] result = array;
++        if (array.length > 0) {
++            // we must create a new array to handle multi-threaded situations
++            // where another thread could access data before we decorate it
++            result = (T[]) Array.newInstance(array.getClass().getComponentType(), 0);
++        }
++        result = collection.toArray(result);
++        Collection<UnmodifiableEntry<K, V>> newCollection = new ArrayList<UnmodifiableEntry<K, V>>();
++        for (int i = 0; i < result.length; i++) {
++            //            result[i] = new UnmodifiableEntry<K,V>((Map.Entry) result[i]);
++            newCollection.add(new UnmodifiableEntry<K, V>((Map.Entry) result[i]));
++        }
++        result = newCollection.toArray(result);
++
++        // check to see if result should be returned straight
++        if (result.length > array.length) {
++            return result;
++        }
++
++        // copy back into input array to fulfil the method contract
++        System.arraycopy(result, 0, array, 0, result.length);
++        if (array.length > result.length) {
++            array[result.length] = null;
++        }
++        return array;
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Implementation of an entry set iterator.
++     */
++    final static class UnmodifiableEntrySetIterator <K,V> extends AbstractIteratorDecorator<Map.Entry<K, V>> {
++
++        protected UnmodifiableEntrySetIterator(Iterator<Map.Entry<K, V>> iterator) {
++            super(iterator);
++        }
++
++        public Map.Entry<K, V> next() {
++            Map.Entry entry = (Map.Entry) iterator.next();
++            return new UnmodifiableEntry<K, V>(entry);
++        }
++
++        public void remove() {
++            throw new UnsupportedOperationException();
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Implementation of a map entry that is unmodifiable.
++     */
++    final static class UnmodifiableEntry <K,V> extends AbstractMapEntryDecorator<K, V> {
++
++        protected UnmodifiableEntry(Map.Entry<K, V> entry) {
++            super(entry);
++        }
++
++        public V setValue(V obj) {
++            throw new UnsupportedOperationException();
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/UnmodifiableMap.java
+@@ -0,0 +1,143 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.IterableMap;
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.collection.UnmodifiableCollection;
++import org.apache.commons.collections15.iterators.EntrySetMapIterator;
++import org.apache.commons.collections15.iterators.UnmodifiableMapIterator;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * Decorates another <code>Map</code> to ensure it can't be altered.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableMap <K,V> extends AbstractMapDecorator<K, V> implements IterableMap<K, V>, Unmodifiable, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 2737023427269031941L;
++
++    /**
++     * Factory method to create an unmodifiable map.
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    public static <K,V> Map<K, V> decorate(Map<K, V> map) {
++        if (map instanceof Unmodifiable) {
++            return map;
++        }
++        return new UnmodifiableMap<K, V>(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    private UnmodifiableMap(Map<K, V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     * @since Commons Collections 3.1
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(map);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     * @since Commons Collections 3.1
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        map = (Map) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public V put(K key, V value) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void putAll(Map<? extends K, ? extends V> mapToCopy) {
++        throw new UnsupportedOperationException();
++    }
++
++    public V remove(Object key) {
++        throw new UnsupportedOperationException();
++    }
++
++    public MapIterator<K, V> mapIterator() {
++        if (map instanceof IterableMap) {
++            MapIterator<K, V> it = ((IterableMap<K, V>) map).mapIterator();
++            return UnmodifiableMapIterator.decorate(it);
++        } else {
++            MapIterator<K, V> it = new EntrySetMapIterator<K, V>(map);
++            return UnmodifiableMapIterator.decorate(it);
++        }
++    }
++
++    public Set<Map.Entry<K, V>> entrySet() {
++        Set<Map.Entry<K, V>> set = super.entrySet();
++        return UnmodifiableEntrySet.decorate(set);
++    }
++
++    public Set<K> keySet() {
++        Set<K> set = super.keySet();
++        return UnmodifiableSet.decorate(set);
++    }
++
++    public Collection<V> values() {
++        Collection<V> coll = super.values();
++        return UnmodifiableCollection.decorate(coll);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/UnmodifiableOrderedMap.java
+@@ -0,0 +1,144 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.MapIterator;
++import org.apache.commons.collections15.OrderedMap;
++import org.apache.commons.collections15.OrderedMapIterator;
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.collection.UnmodifiableCollection;
++import org.apache.commons.collections15.iterators.UnmodifiableMapIterator;
++import org.apache.commons.collections15.iterators.UnmodifiableOrderedMapIterator;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * Decorates another <code>OrderedMap</code> to ensure it can't be altered.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableOrderedMap <K,V> extends AbstractOrderedMapDecorator<K, V> implements Unmodifiable, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 8136428161720526266L;
++
++    /**
++     * Factory method to create an unmodifiable sorted map.
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    public static <K,V> OrderedMap<K, V> decorate(OrderedMap<K, V> map) {
++        if (map instanceof Unmodifiable) {
++            return map;
++        }
++        return new UnmodifiableOrderedMap<K, V>(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    private UnmodifiableOrderedMap(OrderedMap<K, V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     * @since Commons Collections 3.1
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(map);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     * @since Commons Collections 3.1
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        map = (Map<K, V>) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    public MapIterator<K, V> mapIterator() {
++        MapIterator<K, V> it = getOrderedMap().mapIterator();
++        return UnmodifiableMapIterator.decorate(it);
++    }
++
++    public OrderedMapIterator<K, V> orderedMapIterator() {
++        OrderedMapIterator<K, V> it = getOrderedMap().orderedMapIterator();
++        return UnmodifiableOrderedMapIterator.decorate(it);
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public V put(K key, V value) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void putAll(Map<? extends K, ? extends V> mapToCopy) {
++        throw new UnsupportedOperationException();
++    }
++
++    public V remove(Object key) {
++        throw new UnsupportedOperationException();
++    }
++
++    public Set<Map.Entry<K, V>> entrySet() {
++        Set<Map.Entry<K, V>> set = super.entrySet();
++        return UnmodifiableEntrySet.decorate(set);
++    }
++
++    public Set<K> keySet() {
++        Set<K> set = super.keySet();
++        return UnmodifiableSet.decorate(set);
++    }
++
++    public Collection<V> values() {
++        Collection<V> coll = super.values();
++        return UnmodifiableCollection.decorate(coll);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/UnmodifiableSortedMap.java
+@@ -0,0 +1,155 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.map;
++
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.collection.UnmodifiableCollection;
++import org.apache.commons.collections15.set.UnmodifiableSet;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.*;
++
++/**
++ * Decorates another <code>SortedMap</code> to ensure it can't be altered.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableSortedMap <K,V> extends AbstractSortedMapDecorator<K, V> implements Unmodifiable, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 5805344239827376360L;
++
++    /**
++     * Factory method to create an unmodifiable sorted map.
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    public static <K,V> SortedMap<K, V> decorate(SortedMap<K, V> map) {
++        if (map instanceof Unmodifiable) {
++            return map;
++        }
++        return new UnmodifiableSortedMap<K, V>(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if map is null
++     */
++    private UnmodifiableSortedMap(SortedMap<K, V> map) {
++        super(map);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the map out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     * @since Commons Collections 3.1
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(map);
++    }
++
++    /**
++     * Read the map in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     * @since Commons Collections 3.1
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        map = (Map<K, V>) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public V put(K key, V value) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void putAll(Map<? extends K, ? extends V> mapToCopy) {
++        throw new UnsupportedOperationException();
++    }
++
++    public V remove(Object key) {
++        throw new UnsupportedOperationException();
++    }
++
++    public Set<Map.Entry<K, V>> entrySet() {
++        Set<Map.Entry<K, V>> set = super.entrySet();
++        return UnmodifiableEntrySet.decorate(set);
++    }
++
++    public Set<K> keySet() {
++        Set<K> set = super.keySet();
++        return UnmodifiableSet.decorate(set);
++    }
++
++    public Collection<V> values() {
++        Collection<V> coll = super.values();
++        return UnmodifiableCollection.decorate(coll);
++    }
++
++    //-----------------------------------------------------------------------
++    public K firstKey() {
++        return getSortedMap().firstKey();
++    }
++
++    public K lastKey() {
++        return getSortedMap().lastKey();
++    }
++
++    public Comparator<? super K> comparator() {
++        return getSortedMap().comparator();
++    }
++
++    public SortedMap<K, V> subMap(K fromKey, K toKey) {
++        SortedMap<K, V> map = getSortedMap().subMap(fromKey, toKey);
++        return new UnmodifiableSortedMap<K, V>(map);
++    }
++
++    public SortedMap<K, V> headMap(K toKey) {
++        SortedMap<K, V> map = getSortedMap().headMap(toKey);
++        return new UnmodifiableSortedMap<K, V>(map);
++    }
++
++    public SortedMap<K, V> tailMap(K fromKey) {
++        SortedMap<K, V> map = getSortedMap().tailMap(fromKey);
++        return new UnmodifiableSortedMap<K, V>(map);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/map/package.html
+@@ -0,0 +1,54 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:32 pents90 Exp $ -->
++ <!--
++   Copyright 2003-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<BODY>
++<p>
++This package contains implementations of the 
++{@link java.util.Map Map},
++{@link org.apache.commons.collections.IterableMap IterableMap},
++{@link org.apache.commons.collections.OrderedMap OrderedMap} and
++{@link java.util.SortedMap SortedMap} interfaces.
++A Map provides a lookup from a key to a value.
++A number of implementations also support the new MapIterator interface that enables
++simple iteration of map keys and values.
++<p>
++The following implementations are provided:
++<ul>
++<li>CaseInsensitiveMap - map that compares keys in a case insensitive way
++<li>CompositeMap - map that combines multiple maps into a single view
++<li>HashedMap - general purpose HashMap replacement supporting MapIterator
++<li>IdentityMap - map that uses == for comparison instead of equals()
++<li>Flat3Map - designed for good performance at size 3 or less
++<li>LinkedMap - a hash map that maintains insertion order, supporting OrderedMapIterator
++<li>MultiKeyMap - map that provides special methods for using more than one key to access the value
++<li>ReferenceMap - allows the garbage collector to collect keys and values using equals() for comparison
++<li>ReferenceIdentityMap - allows the garbage collector to collect keys and values using == for comparison
++<li>SingletonMap - a fully featured map to hold one key-value pair
++<li>StaticBucketMap - internally synchronized and designed for thread-contentious environments
++</ul>
++<p>
++The following decorators are provided:
++<ul>
++<li>Unmodifiable - ensures the collection cannot be altered
++<li>Predicated - ensures that only elements that are valid according to a predicate can be added
++<li>Typed - ensures that only elements that are of a specific type can be added
++<li>Transformed - transforms each element added
++<li>FixedSize - ensures that the size of the map cannot change
++<li>Lazy - creates objects in the map on demand
++<li>ListOrdered - ensures that insertion order is retained
++</ul>
++</pre>
++</BODY>
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/multimap/MultiHashMap.java
+@@ -0,0 +1,524 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2001-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.multimap;
++
++import org.apache.commons.collections15.iterators.EmptyIterator;
++import org.apache.commons.collections15.MultiMap;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.Serializable;
++import java.util.*;
++
++/**
++ * <code>MultiHashMap</code> is the default implementation of the
++ * {@link org.apache.commons.collections15.MultiMap MultiMap} interface.
++ * <p/>
++ * A <code>MultiMap</code> is like a Map, but with slightly different semantics.
++ * Putting a value into the map will add the value to a Collection at that key.
++ * Getting a value will return a Collection, holding all the values put to that key.
++ * <p/>
++ * This implementation uses an <code>ArrayList</code> as the collection.
++ * The internal storage list is made available without cloning via the
++ * <code>get(Object)</code> and <code>entrySet()</code> methods.
++ * The implementation returns <code>null</code> when there are no values mapped to a key.
++ * <p/>
++ * For example:
++ * <pre>
++ * Number key = new Integer(5);
++ * MultiMap<Number,String> mhm = new MultiHashMap<Number,String>();
++ * mhm.put(key, "A");
++ * mhm.put(key, "B");
++ * mhm.put(key, "C");
++ * Collection<String> coll = mhm.get(key);</pre>
++ * <p/>
++ * <code>list</code> will be a list containing "A", "B", "C".
++ *
++ * @author Christopher Berry
++ * @author James Strachan
++ * @author Steve Downey
++ * @author Stephen Colebourne
++ * @author Julien Buret
++ * @author Matt Hall, John Watkinson, Serhiy Yevtushenko
++ * @version $Revision: 1.2 $ $Date: 2006/06/08 15:19:55 $
++ * @since Commons Collections 2.0
++ */
++public class MultiHashMap<K,V> implements MultiMap<K,V>, Serializable, Cloneable {
++
++    // backed values collection
++    private transient Collection values = null;
++
++    // compatibility with commons-collection releases 2.0/2.1
++    private static final long serialVersionUID = 1943563828307035349L;
++
++    private HashMap<K,Collection<V>> internalMap;
++
++    /**
++     * Constructor.
++     */
++    public MultiHashMap() {
++        internalMap = new HashMap<K, Collection<V>>();
++    }
++
++    /**
++     * Constructor.
++     *
++     * @param initialCapacity the initial map capacity
++     */
++    public MultiHashMap(int initialCapacity) {
++        internalMap = new HashMap<K, Collection<V>>(initialCapacity);
++    }
++
++    /**
++     * Constructor.
++     *
++     * @param initialCapacity the initial map capacity
++     * @param loadFactor      the amount 0.0-1.0 at which to resize the map
++     */
++    public MultiHashMap(int initialCapacity, float loadFactor) {
++        internalMap = new HashMap<K, Collection<V>>(initialCapacity, loadFactor);
++    }
++
++    /**
++     * Constructor that copies the input map creating an independent copy.
++     * <p/>
++     * The values are not cloned.
++     * <p/>
++     *
++     * @param mapToCopy a Map to copy
++     */
++    public MultiHashMap(Map<K, V> mapToCopy) {
++        // be careful of JDK 1.3 vs 1.4 differences
++        internalMap = new HashMap<K, Collection<V>>((int) (mapToCopy.size() * 1.4f));
++        putAll(mapToCopy);
++    }
++
++    /**
++     * Constructor that copies the input MultiMap creating an independent copy.
++     * <p/>
++     * Each internal collection is also cloned.
++     * <p/>
++     * NOTE: From Commons Collections 3.1 this method correctly copies a MultiMap
++     * to form a truly independent new map.
++     *
++     * @param mapToCopy a Map to copy
++     */
++    public MultiHashMap(MultiMap<K,V> mapToCopy) {
++        internalMap = new HashMap<K, Collection<V>>((int) (mapToCopy.size() * 1.4f));
++        for (Iterator<Map.Entry<K,Collection<V>>> it = mapToCopy.entrySet().iterator(); it.hasNext();) {
++            Map.Entry<K,Collection<V>> entry = it.next();
++            Collection<V> coll = entry.getValue();
++            Collection<V> newColl = createCollection(coll);
++            internalMap.put(entry.getKey(), newColl);
++        }
++
++    }
++
++    /**
++     * Read the object during deserialization.
++     */
++    private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
++        // This method is needed because the 1.2/1.3 Java deserialisation called
++        // put and thus messed up that method
++
++        // default read object
++        s.defaultReadObject();
++
++        // problem only with jvm <1.4
++        String version = "1.2";
++        try {
++            version = System.getProperty("java.version");
++        } catch (SecurityException ex) {
++            // ignore and treat as 1.2/1.3
++        }
++
++        if (version.startsWith("1.2") || version.startsWith("1.3")) {
++            for (Iterator<Map.Entry<K,Collection<V>>> iterator = entrySet().iterator(); iterator.hasNext();) {
++                Map.Entry<K,Collection<V>> entry = iterator.next();
++                // put has created a extra collection level, remove it
++                internalMap.put(entry.getKey(), entry.getValue());
++            }
++        }
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets the total size of the map by counting all the values.
++     *
++     * @return the total size of the map counting all values
++     * @since Commons Collections 3.1
++     */
++    public int totalSize() {
++        int total = 0;
++        Collection<Collection<V>> values = internalMap.values();
++        for (Iterator<Collection<V>> it = values.iterator(); it.hasNext();) {
++            Collection<V> coll = it.next();
++            total += coll.size();
++        }
++        return total;
++    }
++
++    /**
++     * Gets the collection mapped to the specified key.
++     * This method is a convenience method to typecast the result of <code>get(key)</code>.
++     *
++     * @param key the key to retrieve
++     * @return the collection mapped to the key, null if no mapping
++     * @since Commons Collections 3.1
++     */
++    public Collection<V> getCollection(Object key) {
++        return internalMap.get(key);
++    }
++
++    /**
++     * Gets the size of the collection mapped to the specified key.
++     *
++     * @param key the key to get size for
++     * @return the size of the collection at the key, zero if key not in map
++     * @since Commons Collections 3.1
++     */
++    public int size(Object key) {
++        Collection<V> coll = getCollection(key);
++        if (coll == null) {
++            return 0;
++        }
++        return coll.size();
++    }
++
++    /**
++     * Gets an iterator for the collection mapped to the specified key.
++     *
++     * @param key the key to get an iterator for
++     * @return the iterator of the collection at the key, empty iterator if key not in map
++     * @since Commons Collections 3.1
++     */
++    public Iterator<V> iterator(Object key) {
++        Collection<V> coll = getCollection(key);
++        if (coll == null) {
++            return EmptyIterator.INSTANCE;
++        }
++        return coll.iterator();
++    }
++
++    /**
++     * Adds the value to the collection associated with the specified key.
++     * <p/>
++     * Unlike a normal <code>Map</code> the previous value is not replaced.
++     * Instead the new value is added to the collection stored against the key.
++     *
++     * @param key   the key to store against
++     * @param value the value to add to the collection at the key
++     * @return the value added if the map changed and null if the map did not change
++     */
++    public V put(K key, V value) {
++        // NOTE:: put is called during deserialization in JDK < 1.4 !!!!!!
++        //        so we must have a readObject()
++        Collection<V> coll = getCollection(key);
++        if (coll == null) {
++            coll = createCollection(null);
++            internalMap.put(key, coll);
++        }
++        boolean results = coll.add(value);
++        return results ? value : null;
++    }
++
++    /**
++     * Adds a collection of values to the collection associated with the specified key.
++     *
++     * @param key    the key to store against
++     * @param values the values to add to the collection at the key, null ignored
++     * @return true if this map changed
++     * @since Commons Collections 3.1
++     */
++    public boolean putAll(K key, Collection<? extends V> values) {
++        if (values == null || values.size() == 0) {
++            return false;
++        }
++        Collection<V> coll = getCollection(key);
++        if (coll == null) {
++            coll = createCollection(values);
++            if (coll.size() == 0) {
++                return false;
++            }
++            internalMap.put(key, coll);
++            return true;
++        } else {
++            return coll.addAll(values);
++        }
++    }
++
++    /**
++     * Checks whether the map contains the value specified.
++     * <p/>
++     * This checks all collections15 against all keys for the value, and thus could be slow.
++     *
++     * @param value the value to search for
++     * @return true if the map contains the value
++     */
++    public boolean containsValue(Object value) {
++        Set<Map.Entry<K,Collection<V>>> pairs = internalMap.entrySet();
++
++        if (pairs == null) {
++            return false;
++        }
++        Iterator<Map.Entry<K,Collection<V>>> pairsIterator = pairs.iterator();
++        while (pairsIterator.hasNext()) {
++            Map.Entry<K,Collection<V>> keyValuePair = pairsIterator.next();
++            Collection<V> coll = keyValuePair.getValue();
++            if (coll.contains(value)) {
++                return true;
++            }
++        }
++        return false;
++    }
++
++    /**
++     * Checks whether the collection at the specified key contains the value.
++     *
++     * @param value the value to search for
++     * @return true if the map contains the value
++     * @since Commons Collections 3.1
++     */
++    public boolean containsValue(Object key, Object value) {
++        Collection<V> coll = getCollection(key);
++        if (coll == null) {
++            return false;
++        }
++        return coll.contains(value);
++    }
++
++    /**
++     * Removes a specific value from map.
++     * <p/>
++     * The item is removed from the collection mapped to the specified key.
++     * Other values attached to that key are unaffected.
++     * <p/>
++     * If the last value for a key is removed, <code>null</code> will be returned
++     * from a subsequant <code>get(key)</code>.
++     *
++     * @param key  the key to remove from
++     * @param item the value to remove
++     * @return the value removed (which was passed in), null if nothing removed
++     */
++    public V remove(Object key, Object item) {
++        Collection valuesForKey = getCollection(key);
++        if (valuesForKey == null) {
++            return null;
++        }
++        valuesForKey.remove(item);
++
++        // remove the list if it is now empty
++        // (saves space, and allows equals to work)
++        if (valuesForKey.isEmpty()) {
++            remove(key);
++        }
++        return (V)item;
++    }
++
++    /**
++     * Clear the map.
++     * <p/>
++     * This clears each collection in the map, and so may be slow.
++     */
++    public void clear() {
++        // For gc, clear each list in the map
++        Set<Map.Entry<K,Collection<V>>> pairs = internalMap.entrySet();
++        Iterator<Map.Entry<K,Collection<V>>> pairsIterator = pairs.iterator();
++        while (pairsIterator.hasNext()) {
++            Map.Entry<K,Collection<V>> keyValuePair = pairsIterator.next();
++            Collection<V> coll = keyValuePair.getValue();
++            coll.clear();
++        }
++        internalMap.clear();
++    }
++
++    public int size() {
++        return internalMap.size();
++    }
++
++    public Collection<V> get(Object key) {
++        return internalMap.get(key);
++    }
++
++    public Collection<V> remove(Object key) {
++        return internalMap.remove(key);
++    }
++
++    public boolean isEmpty() {
++        return internalMap.isEmpty();
++    }
++
++    public boolean containsKey(Object key) {
++        return internalMap.containsKey(key);
++    }
++
++    public void putAll(Map<? extends K, ? extends V> map) {
++        for (K key : map.keySet()) {
++            put(key, map.get(key));
++        }
++    }
++
++    public void putAll(MultiMap<? extends K, ? extends V> map) {
++        for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
++            Map.Entry<? extends K, Collection<? extends V>> entry = (Map.Entry<? extends K, Collection<? extends V>>) it.next();
++            for (V v : entry.getValue()) {
++                put(entry.getKey(), v);
++            }
++        }
++    }
++
++    public Set<K> keySet() {
++        return internalMap.keySet();
++    }
++
++    public Set<Map.Entry<K, Collection<V>>> entrySet() {
++        return internalMap.entrySet();
++    }
++
++    public Map<K, Collection<V>> map() {
++        return internalMap;
++    }
++
++    /**
++     * Gets a collection containing all the values in the map.
++     * <p/>
++     * This returns a collection containing the combination of values from all keys.
++     *
++     * @return a collection view of the values contained in this map
++     */
++    public Collection<V> values() {
++        Collection vs = values;
++        return vs != null ? vs : (values = new Values<V>());
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Inner class to view the elements.
++     */
++    private class Values<T> extends AbstractCollection<V> {
++
++        public Iterator<V> iterator() {
++            return new ValueIterator<V>();
++        }
++
++        public int size() {
++            int compt = 0;
++            Iterator it = iterator();
++            while (it.hasNext()) {
++                it.next();
++                compt++;
++            }
++            return compt;
++        }
++
++        public void clear() {
++            MultiHashMap.this.clear();
++        }
++
++    }
++
++    /**
++     * Inner iterator to view the elements.
++     */
++    private class ValueIterator<T> implements Iterator<V> {
++        private Iterator<Collection<V>> backedIterator;
++        private Iterator<V> tempIterator;
++
++        private ValueIterator() {
++            backedIterator = internalMap.values().iterator();
++        }
++
++        private boolean searchNextIterator() {
++            while (tempIterator == null || tempIterator.hasNext() == false) {
++                if (backedIterator.hasNext() == false) {
++                    return false;
++                }
++                tempIterator = backedIterator.next().iterator();
++            }
++            return true;
++        }
++
++        public boolean hasNext() {
++            return searchNextIterator();
++        }
++
++        public V next() {
++            if (searchNextIterator() == false) {
++                throw new NoSuchElementException();
++            }
++            return tempIterator.next();
++        }
++
++        public void remove() {
++            if (tempIterator == null) {
++                throw new IllegalStateException();
++            }
++            tempIterator.remove();
++        }
++
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Clones the map creating an independent copy.
++     * <p/>
++     * The clone will shallow clone the collections15 as well as the map.
++     *
++     * @return the cloned map
++     */
++    public Object clone() {
++        MultiHashMap<K,V> cloned = new MultiHashMap<K, V>();
++        for (Iterator<Map.Entry<K,Collection<V>>> it = internalMap.entrySet().iterator(); it.hasNext();) {
++            Map.Entry<K,Collection<V>> entry = it.next();
++            for (V v : entry.getValue()) {
++                cloned.put(entry.getKey(), v);
++            }
++        }
++        return cloned;
++    }
++
++    public boolean equals(Object obj) {
++        if (obj instanceof MultiHashMap) {
++            return internalMap.equals(((MultiHashMap)obj).map());
++        } else return false;
++    }
++
++    public int hashCode() {
++        return internalMap.hashCode();
++    }
++
++    /**
++     * Creates a new instance of the map value Collection container.
++     * <p/>
++     * This method can be overridden to use your own collection type.
++     *
++     * @param coll the collection to copy, may be null
++     * @return the new collection
++     */
++    protected Collection<V> createCollection(Collection<? extends V> coll) {
++        if (coll == null) {
++            return new ArrayList<V>();
++        } else {
++            return new ArrayList<V>(coll);
++        }
++    }
++
++    public String toString() {
++        return internalMap.toString();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/overview.html
+@@ -0,0 +1,112 @@
++<!-- $Id: overview.html,v 1.1 2005/10/11 17:05:19 pents90 Exp $ -->
++ <!--
++   Copyright 2003-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<body>
++  <p>
++     Commons-Collections contains implementations, enhancements and utilities
++     that complement the Java Collections Framework.
++  </p>
++  <p>
++     The Apache Jakarta Commons Collections Framework component adds a significant
++     amount of enhancements to the standard JDK collections. These enhancements
++     come in the form of new interfaces, new implementations and utility classes.
++  </p>
++  <p>
++     See also the <code>java.util</code> package for the standard Java collections.
++  </p>
++     
++  <h4>Main features</h4>
++  <p>
++     Commons-Collections defines a number of key interfaces:
++  </p>
++  <table border="1" cellspacing="0" cellpadding="3">
++  <tr bgcolor="#CCCCFF" class="TableHeadingColor">
++    <th>Interface</th><th>Description</th>
++  </tr>
++  <tr>
++    <td>
++      {@link org.apache.commons.collections.Bag}
++    </td>
++    <td valign="top">
++      A new <code>Collection</code> subinterface that stores each object together
++      with the number of occurances. Methods are provided to get the number of
++      occurances, and to add and remove a certain number of that object.
++    </td>
++  </tr>
++  <tr>
++    <td>
++      {@link org.apache.commons.collections.Buffer}
++    </td>
++    <td valign="top">
++      A new <code>Collection</code> subinterface that allows objects to be removed
++      in some well-defined order. Methods enable the next item to be peeked and removed.
++    </td>
++  </tr>
++  <tr>
++    <td>
++      {@link org.apache.commons.collections.BidiMap}
++    </td>
++    <td valign="top">
++      A new <code>Map</code> subinterface that allows lookup from key to value and
++      from value to key with equal ease.
++    </td>
++  </tr>
++  <tr>
++    <td>
++      {@link org.apache.commons.collections.OrderedMap}
++    </td>
++    <td valign="top">
++      A new <code>Map</code> subinterface that is used when a map has an order, but is
++      not sorted. Methods enable bidriectional iteration through the map.
++    </td>
++  </tr>
++  <tr>
++    <td>
++      {@link org.apache.commons.collections.MapIterator}
++    </td>
++    <td valign="top">
++      A new <code>Iterator</code> subinterface specially designed for maps. This iterator
++      avoids the need for entrySet iteration of a map, and is simpler to use.
++    </td>
++  </tr>
++  <tr>
++    <td>
++      {@link org.apache.commons.collections.ResettableIterator}
++    </td>
++    <td valign="top">
++      A new <code>Iterator</code> subinterface that allows the iteration to be reset back
++      to the start. Many iterators in this library have this functionality.
++    </td>
++  </tr>
++  <tr>
++    <td>
++      {@link org.apache.commons.collections.Closure}<br />
++      {@link org.apache.commons.collections.Predicate}<br />
++      {@link org.apache.commons.collections.Transformer}<br />
++      {@link org.apache.commons.collections.Factory}<br />
++    </td>
++    <td valign="top">
++      A group of <i>functor</i> interfaces that provide plugin behaviour to various
++      collections and utilities.
++    </td>
++  </tr>
++  </table>
++  <p>
++     In addition to the interfaces, there are many implementations.
++     Consult each subpackage for full details of these.
++  </p>
++     
++</body>
+\ No newline at end of file
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/package.html
+@@ -0,0 +1,31 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:19 pents90 Exp $ -->
++ <!--
++   Copyright 2003-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<body>
++<p>
++This package contains the interfaces and utilities shared across all the subpackages of this component.
++</p>
++<p>
++The following collection implementations are provided in the package:
++<ul>
++<li>ArrayStack - a non synchronized Stack that follows the same API as java util Stack
++<li>BeanMap - a map that wraps a JavaBean, representing its properties as map keys and values
++<li>ExtendedProperties - extends the Properties class to add extra functionality
++<li>MultiHashMap - an map that stores multiple values against each key
++</ul>
++<p>
++     
++</body>
+\ No newline at end of file
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/AbstractSerializableSetDecorator.java
+@@ -0,0 +1,70 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Set;
++
++/**
++ * Serializable subclass of AbstractSetDecorator.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @since Commons Collections 3.1
++ */
++public abstract class AbstractSerializableSetDecorator <E> extends AbstractSetDecorator<E> implements Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 1229469966212206107L;
++
++    /**
++     * Constructor.
++     */
++    protected AbstractSerializableSetDecorator(Set<E> set) {
++        super(set);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the set out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(collection);
++    }
++
++    /**
++     * Read the set in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        collection = (Collection<E>) in.readObject();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/AbstractSetDecorator.java
+@@ -0,0 +1,62 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.collection.AbstractCollectionDecorator;
++
++import java.util.Set;
++
++/**
++ * Decorates another <code>Set</code> to provide additional behaviour.
++ * <p/>
++ * Methods are forwarded directly to the decorated set.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractSetDecorator <E> extends AbstractCollectionDecorator<E> implements Set<E> {
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     *
++     * @since Commons Collections 3.1
++     */
++    protected AbstractSetDecorator() {
++        super();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    protected AbstractSetDecorator(Set<E> set) {
++        super(set);
++    }
++
++    /**
++     * Gets the set being decorated.
++     *
++     * @return the decorated set
++     */
++    protected Set<E> getSet() {
++        return (Set<E>) getCollection();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/AbstractSortedSetDecorator.java
+@@ -0,0 +1,87 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import java.util.Comparator;
++import java.util.Set;
++import java.util.SortedSet;
++
++/**
++ * Decorates another <code>SortedSet</code> to provide additional behaviour.
++ * <p/>
++ * Methods are forwarded directly to the decorated set.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public abstract class AbstractSortedSetDecorator <E> extends AbstractSetDecorator<E> implements SortedSet<E> {
++
++    /**
++     * Constructor only used in deserialization, do not use otherwise.
++     *
++     * @since Commons Collections 3.1
++     */
++    protected AbstractSortedSetDecorator() {
++        super();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    protected AbstractSortedSetDecorator(Set<E> set) {
++        super(set);
++    }
++
++    /**
++     * Gets the sorted set being decorated.
++     *
++     * @return the decorated set
++     */
++    protected SortedSet<E> getSortedSet() {
++        return (SortedSet<E>) getCollection();
++    }
++
++    //-----------------------------------------------------------------------
++    public SortedSet<E> subSet(E fromElement, E toElement) {
++        return getSortedSet().subSet(fromElement, toElement);
++    }
++
++    public SortedSet<E> headSet(E toElement) {
++        return getSortedSet().headSet(toElement);
++    }
++
++    public SortedSet<E> tailSet(E fromElement) {
++        return getSortedSet().tailSet(fromElement);
++    }
++
++    public E first() {
++        return getSortedSet().first();
++    }
++
++    public E last() {
++        return getSortedSet().last();
++    }
++
++    public Comparator<? super E> comparator() {
++        return getSortedSet().comparator();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/CompositeSet.java
+@@ -0,0 +1,197 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.CollectionUtils;
++import org.apache.commons.collections15.collection.CompositeCollection;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Set;
++
++/**
++ * Decorates a set of other sets to provide a single unified view.
++ * <p/>
++ * Changes made to this set will actually be made on the decorated set.
++ * Add and remove operations require the use of a pluggable strategy. If no
++ * strategy is provided then add and remove are unsupported.
++ *
++ * @author Matt Hall, John Watkinson, Brian McCallister
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public class CompositeSet <E> extends CompositeCollection<E> implements Set<E> {
++    /**
++     * Create an empty CompositeSet
++     */
++    public CompositeSet() {
++        super();
++    }
++
++    /**
++     * Create a CompositeSet with just <code>set</code> composited
++     *
++     * @param set The initial set in the composite
++     */
++    public CompositeSet(Set<E> set) {
++        super(set);
++    }
++
++    /**
++     * Create a composite set with sets as the initial set of composited Sets
++     */
++    public CompositeSet(Set<E>... sets) {
++        super(sets);
++    }
++
++    /**
++     * Add a Set to this composite
++     *
++     * @param c Must implement Set
++     * @throws IllegalArgumentException      if c does not implement java.util.Set
++     *                                       or if a SetMutator is set, but fails to resolve a collision
++     * @throws UnsupportedOperationException if there is no SetMutator set, or
++     *                                       a CollectionMutator is set instead of a SetMutator
++     * @see org.apache.commons.collections15.collection.CompositeCollection.CollectionMutator
++     * @see SetMutator
++     */
++    public synchronized void addComposited(Collection<? extends E> c) {
++        if (!(c instanceof Set)) {
++            throw new IllegalArgumentException("Collections added must implement java.util.Set");
++        }
++
++        for (Iterator i = this.getCollections().iterator(); i.hasNext();) {
++            Set set = (Set) i.next();
++            Collection intersects = CollectionUtils.intersection(set, c);
++            if (intersects.size() > 0) {
++                if (this.mutator == null) {
++                    throw new UnsupportedOperationException("Collision adding composited collection with no SetMutator set");
++                } else if (!(this.mutator instanceof SetMutator)) {
++                    throw new UnsupportedOperationException("Collision adding composited collection to a CompositeSet with a CollectionMutator instead of a SetMutator");
++                }
++                ((SetMutator) this.mutator).resolveCollision(this, set, (Set) c, intersects);
++                if (CollectionUtils.intersection(set, c).size() > 0) {
++                    throw new IllegalArgumentException("Attempt to add illegal entry unresolved by SetMutator.resolveCollision()");
++                }
++            }
++        }
++        super.addComposited((Collection<E>[]) new Collection[]{c});
++    }
++
++    /**
++     * Add two sets to this composite
++     *
++     * @deprecated Superceded by the variable argument implementation of addComposited()
++     * @throws IllegalArgumentException if c or d does not implement java.util.Set
++     */
++    public synchronized void addComposited(Collection<? extends E> c, Collection<? extends E> d) {
++        if (!(c instanceof Set)) throw new IllegalArgumentException("Argument must implement java.util.Set");
++        if (!(d instanceof Set)) throw new IllegalArgumentException("Argument must implement java.util.Set");
++        this.addComposited(new Set[]{(Set) c, (Set) d});
++    }
++
++    /**
++     * Add an array of sets to this composite
++     *
++     * @param comps
++     * @throws IllegalArgumentException if any of the collections15 in comps do not implement Set
++     */
++    public synchronized void addComposited(Collection<? extends E>... comps) {
++        for (int i = comps.length - 1; i >= 0; --i) {
++            this.addComposited(comps[i]);
++        }
++    }
++
++    /**
++     * This can receive either a <code>CompositeCollection.CollectionMutator</code>
++     * or a <code>CompositeSet.SetMutator</code>. If a
++     * <code>CompositeCollection.CollectionMutator</code> is used than conflicts when adding
++     * composited sets will throw IllegalArgumentException
++     * <p/>
++     */
++    public void setMutator(CollectionMutator<E> mutator) {
++        super.setMutator(mutator);
++    }
++    
++    /* Set operations */
++    
++    /**
++     * If a <code>CollectionMutator</code> is defined for this CompositeSet then this
++     * method will be called anyway.
++     *
++     * @param obj Object to be removed
++     * @return true if the object is removed, false otherwise
++     */
++    public boolean remove(Object obj) {
++        for (Iterator i = this.getCollections().iterator(); i.hasNext();) {
++            Set set = (Set) i.next();
++            if (set.contains(obj)) return set.remove(obj);
++        }
++        return false;
++    }
++
++
++    /**
++     * @see Set#equals
++     */
++    public boolean equals(Object obj) {
++        if (obj instanceof Set) {
++            Set set = (Set) obj;
++            if (set.containsAll(this) && set.size() == this.size()) {
++                return true;
++            }
++        }
++        return false;
++    }
++
++    /**
++     * @see Set#hashCode
++     */
++    public int hashCode() {
++        int code = 0;
++        for (Iterator i = this.iterator(); i.hasNext();) {
++            Object next = i.next();
++            code += (next != null ? next.hashCode() : 0);
++        }
++        return code;
++    }
++
++    /**
++     * Define callbacks for mutation operations.
++     * <p/>
++     * Defining remove() on implementations of SetMutator is pointless
++     * as they are never called by CompositeSet.
++     */
++    public static interface SetMutator <E> extends CompositeCollection.CollectionMutator<E> {
++        /**
++         * <p/>
++         * Called when a Set is added to the CompositeSet and there is a
++         * collision between existing and added sets.
++         * </p>
++         * <p/>
++         * If <code>added</code> and <code>existing</code> still have any intersects
++         * after this method returns an IllegalArgumentException will be thrown.
++         * </p>
++         *
++         * @param comp       The CompositeSet being modified
++         * @param existing   The Set already existing in the composite
++         * @param added      the Set being added to the composite
++         * @param intersects the intersection of th existing and added sets
++         */
++        public void resolveCollision(CompositeSet<E> comp, Set<E> existing, Set<E> added, Collection<E> intersects);
++    }
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/ListOrderedSet.java
+@@ -0,0 +1,310 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.iterators.AbstractIteratorDecorator;
++import org.apache.commons.collections15.list.UnmodifiableList;
++
++import java.util.*;
++
++/**
++ * Decorates another <code>Set</code> to ensure that the order of addition
++ * is retained and used by the iterator.
++ * <p/>
++ * If an object is added to the set for a second time, it will remain in the
++ * original position in the iteration.
++ * The order can be observed from the set via the iterator or toArray methods.
++ * <p/>
++ * The ListOrderedSet also has various useful direct methods. These include many
++ * from <code>List</code>, such as <code>get(int)</code>, <code>remove(int)</code>
++ * and <code>indexOf(int)</code>. An unmodifiable <code>List</code> view of
++ * the set can be obtained via <code>asList()</code>.
++ * <p/>
++ * This class cannot implement the <code>List</code> interface directly as
++ * various interface methods (notably equals/hashCode) are incompatable with a set.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @author Henning P. Schmiedehausen
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public class ListOrderedSet <E> extends AbstractSerializableSetDecorator<E> implements Set<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -228664372470420141L;
++
++    /**
++     * Internal list to hold the sequence of objects
++     */
++    protected final List<E> setOrder;
++
++    /**
++     * Factory method to create an ordered set specifying the list and set to use.
++     *
++     * @param set  the set to decorate, must be empty and not null
++     * @param list the list to decorate, must be empty and not null
++     * @throws IllegalArgumentException if set or list is null
++     * @throws IllegalArgumentException if either the set or list is not empty
++     * @since Commons Collections 3.1
++     */
++    public static <E> ListOrderedSet<E> decorate(Set<E> set, List<E> list) {
++        if (set == null) {
++            throw new IllegalArgumentException("Set must not be null");
++        }
++        if (list == null) {
++            throw new IllegalArgumentException("List must not be null");
++        }
++        if (set.size() > 0 || list.size() > 0) {
++            throw new IllegalArgumentException("Set and List must be empty");
++        }
++        return new ListOrderedSet<E>(set, list);
++    }
++
++    /**
++     * Factory method to create an ordered set.
++     * <p/>
++     * An <code>ArrayList</code> is used to retain order.
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    public static <E> ListOrderedSet<E> decorate(Set<E> set) {
++        return new ListOrderedSet<E>(set);
++    }
++
++    /**
++     * Factory method to create an ordered set using the supplied list to retain order.
++     * <p/>
++     * A <code>HashSet</code> is used for the set behaviour.
++     *
++     * @param list the list to decorate, must not be null
++     * @throws IllegalArgumentException if list is null
++     */
++    public static <E> ListOrderedSet<E> decorate(List<E> list) {
++        if (list == null) {
++            throw new IllegalArgumentException("List must not be null");
++        }
++        Set<E> set = new HashSet<E>(list);
++        list.retainAll(set);
++
++        return new ListOrderedSet<E>(set, list);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructs a new empty <code>ListOrderedSet</code> using
++     * a <code>HashSet</code> and an <code>ArrayList</code> internally.
++     *
++     * @since Commons Collections 3.1
++     */
++    public ListOrderedSet() {
++        super(new HashSet<E>());
++        setOrder = new ArrayList<E>();
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    protected ListOrderedSet(Set<E> set) {
++        super(set);
++        setOrder = new ArrayList<E>(set);
++    }
++
++    /**
++     * Constructor that wraps (not copies) the Set and specifies the list to use.
++     * <p/>
++     * The set and list must both be correctly initialised to the same elements.
++     *
++     * @param set  the set to decorate, must not be null
++     * @param list the list to decorate, must not be null
++     * @throws IllegalArgumentException if set or list is null
++     */
++    protected ListOrderedSet(Set<E> set, List<E> list) {
++        super(set);
++        if (list == null) {
++            throw new IllegalArgumentException("List must not be null");
++        }
++        setOrder = list;
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Gets an unmodifiable view of the order of the Set.
++     *
++     * @return an unmodifiable list view
++     */
++    public List<E> asList() {
++        return UnmodifiableList.decorate(setOrder);
++    }
++
++    //-----------------------------------------------------------------------
++    public void clear() {
++        collection.clear();
++        setOrder.clear();
++    }
++
++    public Iterator<E> iterator() {
++        return new OrderedSetIterator<E>(setOrder.iterator(), collection);
++    }
++
++    public boolean add(E object) {
++        if (collection.contains(object)) {
++            // re-adding doesn't change order
++            return collection.add(object);
++        } else {
++            // first add, so add to both set and list
++            boolean result = collection.add(object);
++            setOrder.add(object);
++            return result;
++        }
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        boolean result = false;
++        for (Iterator<? extends E> it = coll.iterator(); it.hasNext();) {
++            E object = it.next();
++            result = result | add(object);
++        }
++        return result;
++    }
++
++    public boolean remove(Object object) {
++        boolean result = collection.remove(object);
++        setOrder.remove(object);
++        return result;
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        boolean result = false;
++        for (Iterator it = coll.iterator(); it.hasNext();) {
++            Object object = it.next();
++            result = result | remove(object);
++        }
++        return result;
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        boolean result = collection.retainAll(coll);
++        if (result == false) {
++            return false;
++        } else if (collection.size() == 0) {
++            setOrder.clear();
++        } else {
++            for (Iterator it = setOrder.iterator(); it.hasNext();) {
++                Object object = it.next();
++                if (collection.contains(object) == false) {
++                    it.remove();
++                }
++            }
++        }
++        return result;
++    }
++
++    public Object[] toArray() {
++        return setOrder.toArray();
++    }
++
++    public <T> T[] toArray(T[] a) {
++        return setOrder.toArray(a);
++    }
++
++    //-----------------------------------------------------------------------
++    public E get(int index) {
++        return setOrder.get(index);
++    }
++
++    public int indexOf(E object) {
++        return setOrder.indexOf(object);
++    }
++
++    public void add(int index, E object) {
++        if (contains(object) == false) {
++            collection.add(object);
++            setOrder.add(index, object);
++        }
++    }
++
++    public boolean addAll(int index, Collection<? extends E> coll) {
++        boolean changed = false;
++        for (Iterator<? extends E> it = coll.iterator(); it.hasNext();) {
++            E object = it.next();
++            if (contains(object) == false) {
++                collection.add(object);
++                setOrder.add(index, object);
++                index++;
++                changed = true;
++            }
++        }
++        return changed;
++    }
++
++    public E remove(int index) {
++        E obj = setOrder.remove(index);
++        remove(obj);
++        return obj;
++    }
++
++    /**
++     * Uses the underlying List's toString so that order is achieved.
++     * This means that the decorated Set's toString is not used, so
++     * any custom toStrings will be ignored.
++     */
++    // Fortunately List.toString and Set.toString look the same
++    public String toString() {
++        return setOrder.toString();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Internal iterator handle remove.
++     */
++    static class OrderedSetIterator <E> extends AbstractIteratorDecorator<E> {
++
++        /**
++         * Object we iterate on
++         */
++        protected final Collection<E> set;
++        /**
++         * Last object retrieved
++         */
++        protected E last;
++
++        private OrderedSetIterator(Iterator<E> iterator, Collection<E> set) {
++            super(iterator);
++            this.set = set;
++        }
++
++        public E next() {
++            last = iterator.next();
++            return last;
++        }
++
++        public void remove() {
++            set.remove(last);
++            iterator.remove();
++            last = null;
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/MapBackedSet.java
+@@ -0,0 +1,163 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Map;
++import java.util.Set;
++
++/**
++ * Decorates a <code>Map</code> to obtain <code>Set</code> behaviour.
++ * <p/>
++ * This class is used to create a <code>Set</code> with the same properties as
++ * the key set of any map. Thus, a ReferenceSet can be created by wrapping a
++ * <code>ReferenceMap</code> in an instance of this class.
++ * <p/>
++ * Most map implementation can be used to create a set by passing in dummy values.
++ * Exceptions include <code>BidiMap</code> implementations, as they require unique values.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.1
++ */
++public final class MapBackedSet <K,V> implements Set<K>, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 6723912213766056587L;
++
++    /**
++     * The map being used as the backing store
++     */
++    protected final Map<K, V> map;
++    /**
++     * The dummyValue to use
++     */
++    protected final V dummyValue;
++
++    /**
++     * Factory method to create a set from a map.
++     *
++     * @param map the map to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    public static <K,V> Set<K> decorate(Map<K, V> map) {
++        return decorate(map, null);
++    }
++
++    /**
++     * Factory method to create a set from a map.
++     *
++     * @param map        the map to decorate, must not be null
++     * @param dummyValue the dummy value to use
++     * @throws IllegalArgumentException if map is null
++     */
++    public static <K,V> Set<K> decorate(Map<K, V> map, V dummyValue) {
++        if (map == null) {
++            throw new IllegalArgumentException("The map must not be null");
++        }
++        return new MapBackedSet<K, V>(map, dummyValue);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param map        the map to decorate, must not be null
++     * @param dummyValue the dummy value to use
++     * @throws IllegalArgumentException if map is null
++     */
++    private MapBackedSet(Map<K, V> map, V dummyValue) {
++        super();
++        this.map = map;
++        this.dummyValue = dummyValue;
++    }
++
++    //-----------------------------------------------------------------------
++    public int size() {
++        return map.size();
++    }
++
++    public boolean isEmpty() {
++        return map.isEmpty();
++    }
++
++    public Iterator<K> iterator() {
++        return map.keySet().iterator();
++    }
++
++    public boolean contains(Object obj) {
++        return map.containsKey(obj);
++    }
++
++    public boolean containsAll(Collection<?> coll) {
++        return map.keySet().containsAll(coll);
++    }
++
++    public boolean add(K obj) {
++        int size = map.size();
++        map.put(obj, dummyValue);
++        return (map.size() != size);
++    }
++
++    public boolean addAll(Collection<? extends K> coll) {
++        int size = map.size();
++        for (Iterator<? extends K> it = coll.iterator(); it.hasNext();) {
++            K obj = it.next();
++            map.put(obj, dummyValue);
++        }
++        return (map.size() != size);
++    }
++
++    public boolean remove(Object obj) {
++        int size = map.size();
++        map.remove(obj);
++        return (map.size() != size);
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        return map.keySet().removeAll(coll);
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        return map.keySet().retainAll(coll);
++    }
++
++    public void clear() {
++        map.clear();
++    }
++
++    public Object[] toArray() {
++        return map.keySet().toArray();
++    }
++
++    public <T> T[] toArray(T[] array) {
++        return map.keySet().toArray(array);
++    }
++
++    public boolean equals(Object obj) {
++        return map.keySet().equals(obj);
++    }
++
++    public int hashCode() {
++        return map.keySet().hashCode();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/PredicatedSet.java
+@@ -0,0 +1,89 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.Predicate;
++import org.apache.commons.collections15.collection.PredicatedCollection;
++
++import java.util.Set;
++
++/**
++ * Decorates another <code>Set</code> to validate that all additions
++ * match a specified predicate.
++ * <p/>
++ * This set exists to provide validation for the decorated set.
++ * It is normally created to decorate an empty set.
++ * If an object cannot be added to the set, an IllegalArgumentException is thrown.
++ * <p/>
++ * One usage would be to ensure that no null entries are added to the set.
++ * <pre>Set set = PredicatedSet.decorate(new HashSet(), NotNullPredicate.INSTANCE);</pre>
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public class PredicatedSet <E> extends PredicatedCollection<E> implements Set<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -684521469108685117L;
++
++    /**
++     * Factory method to create a predicated (validating) set.
++     * <p/>
++     * If there are any elements already in the set being decorated, they
++     * are validated.
++     *
++     * @param set       the set to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @throws IllegalArgumentException if set or predicate is null
++     * @throws IllegalArgumentException if the set contains invalid elements
++     */
++    public static <E> Set<E> decorate(Set<E> set, Predicate<? super E> predicate) {
++        return new PredicatedSet<E>(set, predicate);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the set being decorated, they
++     * are validated.
++     *
++     * @param set       the set to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @throws IllegalArgumentException if set or predicate is null
++     * @throws IllegalArgumentException if the set contains invalid elements
++     */
++    protected PredicatedSet(Set<E> set, Predicate<? super E> predicate) {
++        super(set, predicate);
++    }
++
++    /**
++     * Gets the set being decorated.
++     *
++     * @return the decorated set
++     */
++    protected Set<E> getSet() {
++        return (Set<E>) getCollection();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/PredicatedSortedSet.java
+@@ -0,0 +1,117 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.Predicate;
++
++import java.util.Comparator;
++import java.util.SortedSet;
++
++/**
++ * Decorates another <code>SortedSet</code> to validate that all additions
++ * match a specified predicate.
++ * <p/>
++ * This set exists to provide validation for the decorated set.
++ * It is normally created to decorate an empty set.
++ * If an object cannot be added to the set, an IllegalArgumentException is thrown.
++ * <p/>
++ * One usage would be to ensure that no null entries are added to the set.
++ * <pre>SortedSet set = PredicatedSortedSet.decorate(new TreeSet(), NotNullPredicate.INSTANCE);</pre>
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Paul Jack
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public class PredicatedSortedSet <E> extends PredicatedSet<E> implements SortedSet<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -9110948148132275052L;
++
++    /**
++     * Factory method to create a predicated (validating) sorted set.
++     * <p/>
++     * If there are any elements already in the set being decorated, they
++     * are validated.
++     *
++     * @param set       the set to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @throws IllegalArgumentException if set or predicate is null
++     * @throws IllegalArgumentException if the set contains invalid elements
++     */
++    public static <E> SortedSet<E> decorate(SortedSet<E> set, Predicate<? super E> predicate) {
++        return new PredicatedSortedSet<E>(set, predicate);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the set being decorated, they
++     * are validated.
++     *
++     * @param set       the set to decorate, must not be null
++     * @param predicate the predicate to use for validation, must not be null
++     * @throws IllegalArgumentException if set or predicate is null
++     * @throws IllegalArgumentException if the set contains invalid elements
++     */
++    protected PredicatedSortedSet(SortedSet<E> set, Predicate<? super E> predicate) {
++        super(set, predicate);
++    }
++
++    /**
++     * Gets the sorted set being decorated.
++     *
++     * @return the decorated sorted set
++     */
++    private SortedSet<E> getSortedSet() {
++        return (SortedSet<E>) getCollection();
++    }
++
++    //-----------------------------------------------------------------------
++    public SortedSet<E> subSet(E fromElement, E toElement) {
++        SortedSet sub = getSortedSet().subSet(fromElement, toElement);
++        return new PredicatedSortedSet<E>(sub, predicate);
++    }
++
++    public SortedSet<E> headSet(E toElement) {
++        SortedSet sub = getSortedSet().headSet(toElement);
++        return new PredicatedSortedSet<E>(sub, predicate);
++    }
++
++    public SortedSet<E> tailSet(E fromElement) {
++        SortedSet sub = getSortedSet().tailSet(fromElement);
++        return new PredicatedSortedSet<E>(sub, predicate);
++    }
++
++    public E first() {
++        return getSortedSet().first();
++    }
++
++    public E last() {
++        return getSortedSet().last();
++    }
++
++    public Comparator<? super E> comparator() {
++        return getSortedSet().comparator();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/SynchronizedSet.java
+@@ -0,0 +1,83 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.collection.SynchronizedCollection;
++
++import java.util.Set;
++
++/**
++ * Decorates another <code>Set</code> to synchronize its behaviour for a
++ * multi-threaded environment.
++ * <p/>
++ * Methods are synchronized, then forwarded to the decorated set.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public class SynchronizedSet <E> extends SynchronizedCollection<E> implements Set<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -8304417378626543635L;
++
++    /**
++     * Factory method to create a synchronized set.
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    public static <E> Set<E> decorate(Set<E> set) {
++        return new SynchronizedSet<E>(set);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    protected SynchronizedSet(Set<E> set) {
++        super(set);
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param set  the set to decorate, must not be null
++     * @param lock the lock object to use, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    protected SynchronizedSet(Set<E> set, Object lock) {
++        super(set, lock);
++    }
++
++    /**
++     * Gets the decorated set.
++     *
++     * @return the decorated set
++     */
++    protected Set<E> getSet() {
++        return (Set<E>) collection;
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/SynchronizedSortedSet.java
+@@ -0,0 +1,130 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.collection.SynchronizedCollection;
++
++import java.util.Comparator;
++import java.util.SortedSet;
++
++/**
++ * Decorates another <code>SortedSet</code> to synchronize its behaviour
++ * for a multi-threaded environment.
++ * <p/>
++ * Methods are synchronized, then forwarded to the decorated set.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public class SynchronizedSortedSet <E> extends SynchronizedCollection<E> implements SortedSet<E> {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 2775582861954500111L;
++
++    /**
++     * Factory method to create a synchronized set.
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    public static <E> SortedSet<E> decorate(SortedSet<E> set) {
++        return new SynchronizedSortedSet<E>(set);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    protected SynchronizedSortedSet(SortedSet<E> set) {
++        super(set);
++    }
++
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param set  the set to decorate, must not be null
++     * @param lock the lock object to use, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    protected SynchronizedSortedSet(SortedSet<E> set, Object lock) {
++        super(set, lock);
++    }
++
++    /**
++     * Gets the decorated set.
++     *
++     * @return the decorated set
++     */
++    protected SortedSet<E> getSortedSet() {
++        return (SortedSet<E>) collection;
++    }
++
++    //-----------------------------------------------------------------------
++    public SortedSet<E> subSet(E fromElement, E toElement) {
++        synchronized (lock) {
++            SortedSet set = getSortedSet().subSet(fromElement, toElement);
++            // the lock is passed into the constructor here to ensure that the
++            // subset is synchronized on the same lock as the parent
++            return new SynchronizedSortedSet<E>(set, lock);
++        }
++    }
++
++    public SortedSet<E> headSet(E toElement) {
++        synchronized (lock) {
++            SortedSet set = getSortedSet().headSet(toElement);
++            // the lock is passed into the constructor here to ensure that the
++            // headset is synchronized on the same lock as the parent
++            return new SynchronizedSortedSet<E>(set, lock);
++        }
++    }
++
++    public SortedSet<E> tailSet(E fromElement) {
++        synchronized (lock) {
++            SortedSet<E> set = getSortedSet().tailSet(fromElement);
++            // the lock is passed into the constructor here to ensure that the
++            // tailset is synchronized on the same lock as the parent
++            return new SynchronizedSortedSet<E>(set, lock);
++        }
++    }
++
++    public E first() {
++        synchronized (lock) {
++            return getSortedSet().first();
++        }
++    }
++
++    public E last() {
++        synchronized (lock) {
++            return getSortedSet().last();
++        }
++    }
++
++    public Comparator<? super E> comparator() {
++        synchronized (lock) {
++            return getSortedSet().comparator();
++        }
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/TransformedSet.java
+@@ -0,0 +1,76 @@
++// TODO: Not yet converted - deprecated (by me).
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.Transformer;
++import org.apache.commons.collections15.collection.TransformedCollection;
++
++import java.util.Set;
++
++/**
++ * Decorates another <code>Set</code> to transform objects that are added.
++ * <p/>
++ * The add methods are affected by this class.
++ * Thus objects must be removed or searched for using their transformed form.
++ * For example, if the transformation converts Strings to Integers, you must
++ * use the Integer form to remove objects.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ * <p>
++ * Note: This class cannot support generics without breaking the Collection contract.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public class TransformedSet extends TransformedCollection implements Set {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 306127383500410386L;
++
++    /**
++     * Factory method to create a transforming set.
++     * <p/>
++     * If there are any elements already in the set being decorated, they
++     * are NOT transformed.
++     *
++     * @param set         the set to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @throws IllegalArgumentException if set or transformer is null
++     */
++    public static <I,O> Set<O> decorate(Set<I> set, Transformer<? super I, ? extends O> transformer) {
++        return new TransformedSet(set, transformer);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the set being decorated, they
++     * are NOT transformed.
++     *
++     * @param set         the set to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @throws IllegalArgumentException if set or transformer is null
++     */
++    protected TransformedSet(Set set, Transformer transformer) {
++        super(set, transformer);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/TransformedSortedSet.java
+@@ -0,0 +1,112 @@
++// TODO: Not yet converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.Transformer;
++
++import java.util.Comparator;
++import java.util.SortedSet;
++
++/**
++ * Decorates another <code>SortedSet</code> to transform objects that are added.
++ * <p/>
++ * The add methods are affected by this class.
++ * Thus objects must be removed or searched for using their transformed form.
++ * For example, if the transformation converts Strings to Integers, you must
++ * use the Integer form to remove objects.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public class TransformedSortedSet extends TransformedSet implements SortedSet {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -1675486811351124386L;
++
++    /**
++     * Factory method to create a transforming sorted set.
++     * <p/>
++     * If there are any elements already in the set being decorated, they
++     * are NOT transformed.
++     *
++     * @param set         the set to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @throws IllegalArgumentException if set or transformer is null
++     */
++    public static <I,O> SortedSet<O> decorate(SortedSet<I> set, Transformer<? super I, ? extends O> transformer) {
++        return new TransformedSortedSet(set, transformer);
++    }
++    
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     * <p/>
++     * If there are any elements already in the set being decorated, they
++     * are NOT transformed.
++     *
++     * @param set         the set to decorate, must not be null
++     * @param transformer the transformer to use for conversion, must not be null
++     * @throws IllegalArgumentException if set or transformer is null
++     */
++    protected TransformedSortedSet(SortedSet set, Transformer transformer) {
++        super(set, transformer);
++    }
++
++    /**
++     * Gets the decorated set.
++     *
++     * @return the decorated set
++     */
++    protected SortedSet getSortedSet() {
++        return (SortedSet) collection;
++    }
++
++    //-----------------------------------------------------------------------
++    public Object first() {
++        return getSortedSet().first();
++    }
++
++    public Object last() {
++        return getSortedSet().last();
++    }
++
++    public Comparator comparator() {
++        return getSortedSet().comparator();
++    }
++
++    //-----------------------------------------------------------------------
++    public SortedSet subSet(Object fromElement, Object toElement) {
++        SortedSet set = getSortedSet().subSet(fromElement, toElement);
++        return new TransformedSortedSet(set, transformer);
++    }
++
++    public SortedSet headSet(Object toElement) {
++        SortedSet set = getSortedSet().headSet(toElement);
++        return new TransformedSortedSet(set, transformer);
++    }
++
++    public SortedSet tailSet(Object fromElement) {
++        SortedSet set = getSortedSet().tailSet(fromElement);
++        return new TransformedSortedSet(set, transformer);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/TypedSet.java
+@@ -0,0 +1,59 @@
++// TODO: Not yet converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.functors.InstanceofPredicate;
++
++import java.util.Set;
++
++/**
++ * Decorates another <code>Set</code> to validate that elements
++ * added are of a specific type.
++ * <p/>
++ * The validation of additions is performed via an instanceof test against
++ * a specified <code>Class</code>. If an object cannot be added to the
++ * collection, an IllegalArgumentException is thrown.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @author Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public class TypedSet {
++
++    /**
++     * Factory method to create a typed set.
++     * <p/>
++     * If there are any elements already in the set being decorated, they
++     * are validated.
++     *
++     * @param set  the set to decorate, must not be null
++     * @param type the type to allow into the collection, must not be null
++     * @throws IllegalArgumentException if set or type is null
++     * @throws IllegalArgumentException if the set contains invalid elements
++     */
++    public static Set decorate(Set set, Class type) {
++        return new PredicatedSet(set, InstanceofPredicate.getInstance(type));
++    }
++
++    /**
++     * Restrictive constructor.
++     */
++    protected TypedSet() {
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/TypedSortedSet.java
+@@ -0,0 +1,59 @@
++// TODO: Not yet converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.functors.InstanceofPredicate;
++
++import java.util.SortedSet;
++
++/**
++ * Decorates another <code>SortedSet</code> to validate that elements
++ * added are of a specific type.
++ * <p/>
++ * The validation of additions is performed via an instanceof test against
++ * a specified <code>Class</code>. If an object cannot be added to the
++ * collection, an IllegalArgumentException is thrown.
++ *
++ * @author Stephen Colebourne
++ * @author Matt Hall, John Watkinson, Matthew Hawthorne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public class TypedSortedSet {
++
++    /**
++     * Factory method to create a typed sorted set.
++     * <p/>
++     * If there are any elements already in the set being decorated, they
++     * are validated.
++     *
++     * @param set  the set to decorate, must not be null
++     * @param type the type to allow into the collection, must not be null
++     * @throws IllegalArgumentException if set or type is null
++     * @throws IllegalArgumentException if the set contains invalid elements
++     */
++    public static SortedSet decorate(SortedSet set, Class type) {
++        return new PredicatedSortedSet(set, InstanceofPredicate.getInstance(type));
++    }
++
++    /**
++     * Restrictive constructor.
++     */
++    protected TypedSortedSet() {
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/UnmodifiableSet.java
+@@ -0,0 +1,95 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.iterators.UnmodifiableIterator;
++
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.Set;
++
++/**
++ * Decorates another <code>Set</code> to ensure it can't be altered.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableSet <E> extends AbstractSerializableSetDecorator<E> implements Unmodifiable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = 6499119872185240161L;
++
++    /**
++     * Factory method to create an unmodifiable set.
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    public static <E> Set<E> decorate(Set<E> set) {
++        if (set instanceof Unmodifiable) {
++            return set;
++        }
++        return new UnmodifiableSet<E>(set);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    private UnmodifiableSet(Set<E> set) {
++        super(set);
++    }
++
++    //-----------------------------------------------------------------------
++    public Iterator<E> iterator() {
++        return UnmodifiableIterator.decorate(getCollection().iterator());
++    }
++
++    public boolean add(E object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean remove(Object object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/UnmodifiableSortedSet.java
+@@ -0,0 +1,139 @@
++// GenericsNote: Converted.
++/*
++ *  Copyright 2003-2004 The Apache Software Foundation
++ *
++ *  Licensed under the Apache License, Version 2.0 (the "License");
++ *  you may not use this file except in compliance with the License.
++ *  You may obtain a copy of the License at
++ *
++ *      http://www.apache.org/licenses/LICENSE-2.0
++ *
++ *  Unless required by applicable law or agreed to in writing, software
++ *  distributed under the License is distributed on an "AS IS" BASIS,
++ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++ *  See the License for the specific language governing permissions and
++ *  limitations under the License.
++ */
++package org.apache.commons.collections15.set;
++
++import org.apache.commons.collections15.Unmodifiable;
++import org.apache.commons.collections15.iterators.UnmodifiableIterator;
++
++import java.io.IOException;
++import java.io.ObjectInputStream;
++import java.io.ObjectOutputStream;
++import java.io.Serializable;
++import java.util.Collection;
++import java.util.Iterator;
++import java.util.SortedSet;
++
++/**
++ * Decorates another <code>SortedSet</code> to ensure it can't be altered.
++ * <p/>
++ * This class is Serializable from Commons Collections 3.1.
++ *
++ * @author Matt Hall, John Watkinson, Stephen Colebourne
++ * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:39 $
++ * @since Commons Collections 3.0
++ */
++public final class UnmodifiableSortedSet <E> extends AbstractSortedSetDecorator<E> implements Unmodifiable, Serializable {
++
++    /**
++     * Serialization version
++     */
++    private static final long serialVersionUID = -725356885467962424L;
++
++    /**
++     * Factory method to create an unmodifiable set.
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    public static <E> SortedSet<E> decorate(SortedSet<E> set) {
++        if (set instanceof Unmodifiable) {
++            return set;
++        }
++        return new UnmodifiableSortedSet<E>(set);
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Write the collection out using a custom routine.
++     *
++     * @param out the output stream
++     * @throws IOException
++     */
++    private void writeObject(ObjectOutputStream out) throws IOException {
++        out.defaultWriteObject();
++        out.writeObject(collection);
++    }
++
++    /**
++     * Read the collection in using a custom routine.
++     *
++     * @param in the input stream
++     * @throws IOException
++     * @throws ClassNotFoundException
++     */
++    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
++        in.defaultReadObject();
++        collection = (Collection<E>) in.readObject();
++    }
++
++    //-----------------------------------------------------------------------
++    /**
++     * Constructor that wraps (not copies).
++     *
++     * @param set the set to decorate, must not be null
++     * @throws IllegalArgumentException if set is null
++     */
++    private UnmodifiableSortedSet(SortedSet<E> set) {
++        super(set);
++    }
++
++    //-----------------------------------------------------------------------
++    public Iterator<E> iterator() {
++        return UnmodifiableIterator.decorate(getCollection().iterator());
++    }
++
++    public boolean add(E object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean addAll(Collection<? extends E> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public void clear() {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean remove(Object object) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean removeAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    public boolean retainAll(Collection<?> coll) {
++        throw new UnsupportedOperationException();
++    }
++
++    //-----------------------------------------------------------------------
++    public SortedSet<E> subSet(E fromElement, E toElement) {
++        SortedSet<E> sub = getSortedSet().subSet(fromElement, toElement);
++        return new UnmodifiableSortedSet<E>(sub);
++    }
++
++    public SortedSet<E> headSet(E toElement) {
++        SortedSet sub = getSortedSet().headSet(toElement);
++        return new UnmodifiableSortedSet<E>(sub);
++    }
++
++    public SortedSet<E> tailSet(E fromElement) {
++        SortedSet<E> sub = getSortedSet().tailSet(fromElement);
++        return new UnmodifiableSortedSet<E>(sub);
++    }
++
++}
+--- /dev/null
++++ libjung-java/collections15/org/apache/commons/collections15/set/package.html
+@@ -0,0 +1,42 @@
++<!-- $Id: package.html,v 1.1 2005/10/11 17:05:39 pents90 Exp $ -->
++ <!--
++   Copyright 2003-2004 The Apache Software Foundation
++
++   Licensed under the Apache License, Version 2.0 (the "License");
++   you may not use this file except in compliance with the License.
++   You may obtain a copy of the License at
++
++       http://www.apache.org/licenses/LICENSE-2.0
++
++   Unless required by applicable law or agreed to in writing, software
++   distributed under the License is distributed on an "AS IS" BASIS,
++   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++   See the License for the specific language governing permissions and
++   limitations under the License.
++  -->
++<BODY>
++<p>
++This package contains implementations of the
++{@link java.util.Set Set} and
++{@link java.util.SortedSet SortedSet} interfaces.
++<p>
++The implementations are in the form of direct implementations and decorators.
++A decorator wraps another implementation of the interface to add some
++specific additional functionality.
++<p>
++The following implementations are provided in the package:
++<ul>
++<li>CompositeSet - a set that combines multiple sets into one
++</ul>
++The following decorators are provided in the package:
++<ul>
++<li>Synchronized - synchronizes method access for multi-threaded environments
++<li>Unmodifiable - ensures the collection cannot be altered
++<li>Predicated - ensures that only elements that are valid according to a predicate can be added
++<li>Typed - ensures that only elements that are of a specific type can be added
++<li>Transformed - transforms each element added
++<li>ListOrdered - ensures that insertion order is retained
++<li>MapBackedSet - a set formed by decorating a Map
++</ul>
++</pre>
++</BODY>
diff --git a/debian/patches/series b/debian/patches/series
new file mode 100644
index 0000000..692f4e8
--- /dev/null
+++ b/debian/patches/series
@@ -0,0 +1 @@
+collections15
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..dac7856
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,51 @@
+#!/usr/bin/make -f
+
+DH_VERBOSE := 1
+
+# some helpful variables - uncomment them if needed
+# shamelessly stolen from http://jmtd.net/log/awk/
+#DEBVERS        := $(shell dpkg-parsechangelog | awk '/^Version:/ {print $$2}')
+#VERSION        := $(shell echo '$(DEBVERS)' | sed -e 's/^[0-9]*://' -e 's/-.*//')
+#DEBFLAVOR      := $(shell dpkg-parsechangelog | awk '/^Distribution:/ {print $$2}')
+#DEBPKGNAME     := $(shell dpkg-parsechangelog | awk '/^Source:/ {print $$2}')
+#DEBIAN_BRANCH  := $(shell awk 'BEGIN{FS="[= ]+"} /debian-branch/ {print $$2}' debian/gbp.conf)
+#GIT_TAG        := $(subst ~,_,$(VERSION))
+
+# alternatively to manually set those variables you can
+#  include /usr/share/cdbs/1/rules/buildvars.mk
+# and use what is set there.  Any hint whether dh might set variables in
+# a similar manner are welcome.
+
+export JAVA_HOME=/usr/lib/jvm/default-java
+export CLASSPATH=/usr/share/java/commons-collections4.jar:/usr/share/java/colt.jar:./collections15.jar:./jung-api-2.0.1.jar
+
+%:
+	dh $@ --with javahelper
+
+override_dh_auto_build:
+	for jar in *.jar; do mkdir $${jar%%.jar}; pushd $${jar%%.jar}; \
+		unzip ../$${jar}; popd; done
+		#find . -type f | xargs sed -i -e \
+		#'s/org.apache.commons.collections15/org.apache.commons.collections4/' \
+		#-e 's/org.apache.commons.collections4.Buffer/java.util.Queue/' \
+		#-e 's/org.apache.commons.collections4.buffer.UnboundedFifoBuffer/java.util.LinkedList/' \
+		#-e 's/UnboundedFifoBuffer/LinkedList/' \
+		#-e 's/Buffer/Queue/' \
+		#-e 's/LazyMap.decorate/LazyMap.lazyMap/' \
+		#-e 's/MapTransformer.getInstance/MapTransformer.mapTransformer/' \
+		#-e 's/ChainedTransformer.getInstance/ChainedTransformer.chainedTransformer/' \
+		#-e 's/CloneTransformer.getInstance/CloneTransformer.cloneTransformer/' ;
+		# this _almost_ worked :-(
+	jh_build collections15.jar collections15
+	jh_build jung-api-2.0.1.jar jung-api-2.0.1-sources
+	jh_build jung-algorithms-2.0.1.jar jung-algorithms-2.0.1-sources
+	jh_build jung-graph-impl-2.0.1.jar jung-graph-impl-2.0.1-sources
+
+override_dh_auto_install:
+	jh_installlibs jung-api-2.0.1.jar
+	jh_installlibs collections15.jar
+	jh_installlibs jung-algorithms-2.0.1.jar
+	jh_installlibs jung-graph-impl-2.0.1.jar
+
+#get-orig-source:
+#	. debian/get-orig-source
diff --git a/debian/source/format b/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/debian/upstream/metadata b/debian/upstream/metadata
new file mode 100644
index 0000000..d8b5812
--- /dev/null
+++ b/debian/upstream/metadata
@@ -0,0 +1,12 @@
+Reference:
+  Author: 
+  Title: 
+  Journal: 
+  Year: 
+  Volume: 
+  Number: 
+  Pages: 
+  DOI: 
+  PMID:
+  URL: 
+  eprint: 
diff --git a/debian/watch b/debian/watch
new file mode 100644
index 0000000..053abcf
--- /dev/null
+++ b/debian/watch
@@ -0,0 +1,37 @@
+version=3
+
+# Uncomment to examine a Webpage
+# <Webpage URL> <string match>
+#http://www.example.com/downloads.php #PACKAGE#-(.*)\.tar\.gz
+
+# Uncomment to examine a Webserver directory
+#http://www.example.com/pub/#PACKAGE#-(.*)\.tar\.gz
+
+# Uncommment to examine a FTP server
+#ftp://ftp.example.com/pub/#PACKAGE#-(.*)\.tar\.gz debian uupdate
+
+# Uncomment to find new files on sourceforge
+# http://sf.net/#PACKAGE#/#PACKAGE#-(\d[\d\.]+)\.(?:tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz)))
+
+# Uncomment to find new files on GooglePages
+# http://code.google.com/p/#PACKAGE#/downloads/list?can=1 \
+#  .*/#PACKAGE#-([-.\d]+)\.(?:tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz))|zip)
+
+# Uncomment to find new files on Github
+#  - when using releases:
+# https://github.com/#GITHUBUSER#/#PACKAGE#/releases .*/archive/#PREFIX#(\d[\d.-]+)\.(?:tar(?:\.gz|\.bz2)?|tgz)
+#  - when using tags
+# https://github.com/#GITHUBUSER#/#PACKAGE#/tags .*/#PREFIX#(\d.*)\.(?:tgz|tbz2|txz|tar\.(?:gz|bz2|xz))
+# Remark: frequently you can do s/#PREFIX#/v?/ since 'v' or nothing is quite common but there are other prefixes possible
+
+# PyPi repository of Python modules
+#  see https://lists.debian.org/debian-python/2015/02/msg00027.html
+# http://pypi.debian.net/#module#/#module#-(.+)\.(?:tar(?:\.gz|\.bz2)?|tgz)
+
+# if tweaking of source is needed
+# \
+# debian debian/get-orig-source
+
+# if you need to repack and choose +dfsg prefix
+# opts=dversionmangle=s/[~\+]dfsg[0-9]*// \
+#

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/libjung-java.git



More information about the debian-med-commit mailing list