         // nothing needed
     }
 
-    // documentation inherited
+    // from Hashable
     public function hashCode () :int
     {
         return clusterOid;
     }
 
+    // from Hashable
+    public function equals (o :Object) :Boolean
+    {
+        return (o is Cluster) && ((o as Cluster).clusterOid == this.clusterOid);
+    }
+
     /**
      * Generates a string representation of this instance.
      */
-    override public function toString () :String
+    public function toString () :String
     {
-        return super.toString() + ", clusterOid=" + clusterOid;
+        return "x=" + x + ", y=" + y + ", width=" + width + ", height=" + height +
+            ", clusterOid=" + clusterOid;
     }
 
     // documentation inherited from interface DSet_Entry

    // documentation inherited from interface Streamable
    public function readObject (ins :ObjectInputStream) :void
    {
        clusterOid = ins.readInt();
    }

    // documentation inherited from interface Streamable
    public function writeObject (out :ObjectOutputStream) :void
    {
        out.writeInt(clusterOid);
    }

    /** Used for {@link #getKey}. */
    protected var _key :int;
}
}

/**
 * Contains information on clusters.
 */
public class Cluster
    implements DSet_Entry, Streamable, Hashable
{
    /** The bounding rectangle of this cluster. */
    public var x :int;
    public var y :int;
    public var width :int;
    public var height :int;

    /** A unique identifier for this cluster (also the distributed object
     * id of the cluster chat object). */
    public var clusterOid :int;
