Index: /applications/editors/josm/plugins/smed2/js57toosm/build.xml
===================================================================
--- /applications/editors/josm/plugins/smed2/js57toosm/build.xml	(revision 30283)
+++ /applications/editors/josm/plugins/smed2/js57toosm/build.xml	(revision 30284)
@@ -3,5 +3,7 @@
   <property name="build" location="build"/>
   <property name="jarfile" location="./js57toosm.jar"/>
-
+  <property name="ant.build.javac.target" value="1.6"/>
+  <property name="ant.build.javac.source" value="1.6"/>
+    
   <target name="init">
     <mkdir dir="${build}"/>
Index: /applications/editors/josm/plugins/smed2/js57toosm/src/js57toosm/Js57toosm.java
===================================================================
--- /applications/editors/josm/plugins/smed2/js57toosm/src/js57toosm/Js57toosm.java	(revision 30283)
+++ /applications/editors/josm/plugins/smed2/js57toosm/src/js57toosm/Js57toosm.java	(revision 30284)
@@ -13,5 +13,4 @@
 import java.util.*;
 
-import s57.S57map.Prim;
 import s57.S57obj;
 import s57.S57obj.*;
@@ -20,8 +19,7 @@
 import s57.S57val;
 import s57.S57val.*;
-import s57.S57dat;
-import s57.S57dat.*;
 import s57.S57map;
 import s57.S57map.*;
+import s57.S57dec;
 
 public class Js57toosm {
@@ -33,4 +31,6 @@
 	public static void main(String[] args) throws IOException {
 
+		ArrayList<Long> done = new ArrayList<Long>();
+
 		if (args.length < 1) {
 			System.err.println("Usage: java -jar js57toosm.jar S57_filename [types_filename]");
@@ -49,184 +49,9 @@
 		
 		map = new S57map();
-		S57dat.rnum = 0;
-
-		byte[] leader = new byte[24];
-		boolean ddr = false;
-		int length;
-		int fields;
-		int mapfl, mapfp, mapts, entry;
-		String tag;
-		int len;
-		int pos;
-		boolean inFeature = false;
-
-		double comf = 1;
-		double somf = 1;
-		long name = 0;
-		S57map.Nflag nflag = Nflag.ANON;
-		S57map.Pflag pflag = S57map.Pflag.NOSP;
-		long objl = 0;
-		double minlat = 90, minlon = 180, maxlat = -90, maxlon = -180;
-		
-		ArrayList<Long> done = new ArrayList<Long>();
-
-		while (in.read(leader) == 24) {
-			length = Integer.parseInt(new String(leader, 0, 5)) - 24;
-			ddr = (leader[6] == 'L');
-			fields = Integer.parseInt(new String(leader, 12, 5)) - 24;
-			mapfl = leader[20] - '0';
-			mapfp = leader[21] - '0';
-			mapts = leader[23] - '0';
-			entry = mapfl + mapfp + mapts;
-			byte[] record = new byte[length];
-			if (in.read(record) != length)
-				break;
-			for (int idx = 0; idx < fields-1; idx += entry) {
-				tag = new String(record, idx, mapts);
-				len = Integer.parseInt(new String(record, idx+mapts, mapfl));
-				pos = Integer.parseInt(new String(record, idx+mapts+mapfl, mapfp));
-				if (!ddr) {
-					switch (tag) {
-					case "0001":
-						int i8rn = ((Long) S57dat.getSubf(record, fields + pos, S57field.I8RI, S57subf.I8RN)).intValue();
-						if (i8rn != ++S57dat.rnum) {
-							out.println("Out of order record ID");
-							in.close();
-							System.exit(-1);
-						}
-						break;
-					case "DSPM":
-						comf = (double) (Long) S57dat.getSubf(record, fields + pos, S57field.DSPM, S57subf.COMF);
-						somf = (double) (Long) S57dat.getSubf(S57subf.SOMF);
-						break;
-					case "FRID":
-						inFeature = true;
-						switch ((int)((long)S57dat.getSubf(record, fields + pos, S57field.FRID, S57subf.PRIM))) {
-						case 1:
-							pflag = S57map.Pflag.POINT;
-							break;
-						case 2:
-							pflag = S57map.Pflag.LINE;
-							break;
-						case 3:
-							pflag = S57map.Pflag.AREA;
-							break;
-						default:
-							pflag = S57map.Pflag.NOSP;
-						}
-						objl = (long)S57dat.getSubf(S57subf.OBJL);
-						break;
-					case "FOID":
-						name = (long) S57dat.getSubf(record, fields + pos, S57field.FOID, S57subf.LNAM);
-						map.newFeature(name, pflag, objl);
-						break;
-					case "ATTF":
-						S57dat.setField(record, fields + pos, S57field.ATTF, len);
-						do {
-							long attl = (long) S57dat.getSubf(S57subf.ATTL);
-							String atvl = (String) S57dat.getSubf(S57subf.ATVL);
-							if (!atvl.isEmpty()) {
-								map.newAtt(attl, atvl);
-							}
-						} while (S57dat.more());
-						break;
-					case "FFPT":
-						S57dat.setField(record, fields + pos, S57field.FFPT, len);
-						do {
-							name = (long) S57dat.getSubf(S57subf.LNAM);
-							int rind = ((Long) S57dat.getSubf(S57subf.RIND)).intValue();
-							S57dat.getSubf(S57subf.COMT);
-							map.newObj(name, rind);
-						} while (S57dat.more());
-						break;
-					case "FSPT":
-						S57dat.setField(record, fields + pos, S57field.FSPT, len);
-						do {
-							name = (Long) S57dat.getSubf(S57subf.NAME) << 16;
-							map.newPrim(name, (long) S57dat.getSubf(S57subf.ORNT), (long) S57dat.getSubf(S57subf.USAG));
-							S57dat.getSubf(S57subf.MASK);
-						} while (S57dat.more());
-						break;
-					case "VRID":
-						inFeature = false;
-						name = (long) S57dat.getSubf(record, fields + pos, S57field.VRID, S57subf.RCNM);
-						switch ((int) name) {
-						case 110:
-							nflag = Nflag.ISOL;
-							break;
-						case 120:
-							nflag = Nflag.CONN;
-							break;
-						default:
-							nflag = Nflag.ANON;
-							break;
-						}
-						name <<= 32;
-						name += (Long) S57dat.getSubf(S57subf.RCID);
-						name <<= 16;
-						if (nflag == Nflag.ANON) {
-							map.newEdge(name);
-						}
-						break;
-					case "VRPT":
-						S57dat.setField(record, fields + pos, S57field.VRPT, len);
-						do {
-							long conn = (Long) S57dat.getSubf(S57subf.NAME) << 16;
-							int topi = ((Long) S57dat.getSubf(S57subf.TOPI)).intValue();
-							map.addConn(conn, topi);
-							S57dat.getSubf(S57subf.MASK);
-						} while (S57dat.more());
-						break;
-					case "SG2D":
-						S57dat.setField(record, fields + pos, S57field.SG2D, len);
-						do {
-							double lat = (double) ((Long) S57dat.getSubf(S57subf.YCOO)) / comf;
-							double lon = (double) ((Long) S57dat.getSubf(S57subf.XCOO)) / comf;
-							if (nflag == Nflag.ANON) {
-								map.newNode(++name, lat, lon, nflag);
-							} else {
-								map.newNode(name, lat, lon, nflag);
-							}
-							if (lat < minlat)
-								minlat = lat;
-							if (lat > maxlat)
-								maxlat = lat;
-							if (lon < minlon)
-								minlon = lon;
-							if (lon > maxlon)
-								maxlon = lon;
-						} while (S57dat.more());
-						break;
-					case "SG3D":
-						S57dat.setField(record, fields + pos, S57field.SG3D, len);
-						do {
-							double lat = (double) ((Long) S57dat.getSubf(S57subf.YCOO)) / comf;
-							double lon = (double) ((Long) S57dat.getSubf(S57subf.XCOO)) / comf;
-							double depth = (double) ((Long) S57dat.getSubf(S57subf.VE3D)) / somf;
-							map.newNode(name++, lat, lon, depth);
-							if (lat < minlat)
-								minlat = lat;
-							if (lat > maxlat)
-								maxlat = lat;
-							if (lon < minlon)
-								minlon = lon;
-							if (lon > maxlon)
-								maxlon = lon;
-						} while (S57dat.more());
-						break;
-					}
-				}
-				if (inFeature) {
-					map.endFeature();
-					inFeature = false;
-				}
-			}
-		}
-		map.endFile();
-		in.close();
-
-		out.println("<?xml version='1.0' encoding='UTF-8'?>");
-		out.println("<osm version='0.6' generator='js57toosm'>");
-		out.println("<bounds minlat='" + minlat + "' minlon='" + minlon + "' maxlat='" + maxlat + "' maxlon='" + maxlon + "'/>");
+		MapBounds bounds = S57dec.decodeFile(in, types, map);
+
+		out.format("<?xml version='1.0' encoding='UTF-8'?>");
+		out.format("<osm version='0.6' generator='js57toosm'>");
+		out.format("<bounds minlat='%.8f' minlon='%.8f' maxlat='%.8f' maxlon='%.8f'/>", bounds.minlat, bounds.minlon, bounds.maxlat, bounds.maxlon);
 
 		for (long id : map.index.keySet()) {
@@ -261,5 +86,5 @@
 			if (!type.isEmpty() && (types.isEmpty() || types.contains(feature.type))) {
 				if (feature.reln == Rflag.MASTER) {
-					if (feature.geom.prim == Pflag.LINE) {
+					if ((feature.geom.prim == Pflag.LINE) || ((feature.geom.prim == Pflag.AREA) && (feature.geom.outers == 1) && (feature.geom.inners == 0))) {
 						GeomIterator git = map.new GeomIterator(feature.geom);
 						while (git.hasComp()) {
Index: /applications/editors/josm/plugins/smed2/src/s57/S57dat.java
===================================================================
--- /applications/editors/josm/plugins/smed2/src/s57/S57dat.java	(revision 30283)
+++ /applications/editors/josm/plugins/smed2/src/s57/S57dat.java	(revision 30284)
@@ -134,4 +134,30 @@
 	}
 
+	private static final EnumMap<S57field, String> FldStr = new EnumMap<S57field, String>(S57field.class);
+	static {
+		FldStr.put(S57field.I8RI, "0001");
+		FldStr.put(S57field.DSID, "DSID"); FldStr.put(S57field.DSSI, "DSSI"); FldStr.put(S57field.DSPM, "DSPM"); FldStr.put(S57field.DSPR, "DSPR");
+		FldStr.put(S57field.DSRC, "DSRC"); FldStr.put(S57field.DSHT, "DSHT"); FldStr.put(S57field.DSAC, "DSAC"); FldStr.put(S57field.CATD, "CATD");
+		FldStr.put(S57field.CATX, "CATX"); FldStr.put(S57field.DDDF, "DDDF"); FldStr.put(S57field.DDDR, "DDDR"); FldStr.put(S57field.DDDI, "DDDI");
+		FldStr.put(S57field.DDOM, "DDOM"); FldStr.put(S57field.DDRF, "DDRF"); FldStr.put(S57field.DDSI, "DDSI"); FldStr.put(S57field.DDSC, "DDSC");
+		FldStr.put(S57field.FRID, "FRID"); FldStr.put(S57field.FOID, "FOID"); FldStr.put(S57field.ATTF, "ATTF"); FldStr.put(S57field.NATF, "NATF");
+		FldStr.put(S57field.FFPC, "FFPC"); FldStr.put(S57field.FFPT, "FFPT"); FldStr.put(S57field.FFPC, "FFPC"); FldStr.put(S57field.FSPT, "FSPT");
+		FldStr.put(S57field.VRID, "VRID"); FldStr.put(S57field.ATTV, "ATTV"); FldStr.put(S57field.VRPC, "VRPC"); FldStr.put(S57field.VRPT, "VRPT");
+		FldStr.put(S57field.SGCC, "SGCC"); FldStr.put(S57field.SG2D, "SG2D"); FldStr.put(S57field.SG3D, "SG3D"); FldStr.put(S57field.ARCC, "ARCC");
+		FldStr.put(S57field.AR2D, "AR2D"); FldStr.put(S57field.EL2D, "EL2D"); FldStr.put(S57field.CT2D, "CT2D"); 
+	}
+	
+	public static String stringField (S57field field) {
+		return FldStr.get(field);
+	}
+	
+	public static S57field enumField (String field) {
+		for (S57field fld : FldStr.keySet()) {
+			if (FldStr.get(fld).equals(field))
+				return fld;
+		}
+		return null;
+	}
+
 	private static byte[] buffer;
 	private static int offset;
Index: /applications/editors/josm/plugins/smed2/src/s57/S57dec.java
===================================================================
--- /applications/editors/josm/plugins/smed2/src/s57/S57dec.java	(revision 30284)
+++ /applications/editors/josm/plugins/smed2/src/s57/S57dec.java	(revision 30284)
@@ -0,0 +1,202 @@
+/* Copyright 2013 Malcolm Herring
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * For a copy of the GNU General Public License, see <http://www.gnu.org/licenses/>.
+ */
+
+package s57;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import s57.S57dat.*;
+import s57.S57map.*;
+import s57.S57obj.*;
+
+public class S57dec {
+
+	public static MapBounds decodeFile(FileInputStream in, ArrayList<Obj> types, S57map map) throws IOException {
+		S57dat.rnum = 0;
+		byte[] leader = new byte[24];
+		boolean ddr = false;
+		int length;
+		int fields;
+		int mapfl, mapfp, mapts, entry;
+		String tag;
+		int len;
+		int pos;
+		boolean inFeature = false;
+
+		double comf = 1;
+		double somf = 1;
+		long name = 0;
+		S57map.Nflag nflag = Nflag.ANON;
+		S57map.Pflag pflag = S57map.Pflag.NOSP;
+		long objl = 0;
+		MapBounds bounds = map.new MapBounds();
+		
+		while (in.read(leader) == 24) {
+			length = Integer.parseInt(new String(leader, 0, 5)) - 24;
+			ddr = (leader[6] == 'L');
+			fields = Integer.parseInt(new String(leader, 12, 5)) - 24;
+			mapfl = leader[20] - '0';
+			mapfp = leader[21] - '0';
+			mapts = leader[23] - '0';
+			entry = mapfl + mapfp + mapts;
+			byte[] record = new byte[length];
+			if (in.read(record) != length)
+				break;
+			for (int idx = 0; idx < fields-1; idx += entry) {
+				tag = new String(record, idx, mapts);
+				len = Integer.parseInt(new String(record, idx+mapts, mapfl));
+				pos = Integer.parseInt(new String(record, idx+mapts+mapfl, mapfp));
+				if (!ddr) {
+					switch (S57dat.enumField(tag)) {
+					case I8RI:
+						int i8rn = ((Long) S57dat.getSubf(record, fields + pos, S57field.I8RI, S57subf.I8RN)).intValue();
+						if (i8rn != ++S57dat.rnum) {
+							System.err.println("Out of order record ID");
+							in.close();
+							System.exit(-1);
+						}
+						break;
+					case DSPM:
+						comf = (double) (Long) S57dat.getSubf(record, fields + pos, S57field.DSPM, S57subf.COMF);
+						somf = (double) (Long) S57dat.getSubf(S57subf.SOMF);
+						break;
+					case FRID:
+						inFeature = true;
+						switch (((Long)S57dat.getSubf(record, fields + pos, S57field.FRID, S57subf.PRIM)).intValue()) {
+						case 1:
+							pflag = S57map.Pflag.POINT;
+							break;
+						case 2:
+							pflag = S57map.Pflag.LINE;
+							break;
+						case 3:
+							pflag = S57map.Pflag.AREA;
+							break;
+						default:
+							pflag = S57map.Pflag.NOSP;
+						}
+						objl = (Long)S57dat.getSubf(S57subf.OBJL);
+						break;
+					case FOID:
+						name = (Long) S57dat.getSubf(record, fields + pos, S57field.FOID, S57subf.LNAM);
+						map.newFeature(name, pflag, objl);
+						break;
+					case ATTF:
+						S57dat.setField(record, fields + pos, S57field.ATTF, len);
+						do {
+							long attl = (Long) S57dat.getSubf(S57subf.ATTL);
+							String atvl = ((String) S57dat.getSubf(S57subf.ATVL)).trim();
+							if (!atvl.isEmpty()) {
+								map.newAtt(attl, atvl);
+							}
+						} while (S57dat.more());
+						break;
+					case FFPT:
+						S57dat.setField(record, fields + pos, S57field.FFPT, len);
+						do {
+							name = (Long) S57dat.getSubf(S57subf.LNAM);
+							int rind = ((Long) S57dat.getSubf(S57subf.RIND)).intValue();
+							S57dat.getSubf(S57subf.COMT);
+							map.newObj(name, rind);
+						} while (S57dat.more());
+						break;
+					case FSPT:
+						S57dat.setField(record, fields + pos, S57field.FSPT, len);
+						do {
+							name = (Long) S57dat.getSubf(S57subf.NAME) << 16;
+							map.newPrim(name, (Long) S57dat.getSubf(S57subf.ORNT), (Long) S57dat.getSubf(S57subf.USAG));
+							S57dat.getSubf(S57subf.MASK);
+						} while (S57dat.more());
+						break;
+					case VRID:
+						inFeature = false;
+						name = (long) (Long)S57dat.getSubf(record, fields + pos, S57field.VRID, S57subf.RCNM);
+						switch ((int) name) {
+						case 110:
+							nflag = Nflag.ISOL;
+							break;
+						case 120:
+							nflag = Nflag.CONN;
+							break;
+						default:
+							nflag = Nflag.ANON;
+							break;
+						}
+						name <<= 32;
+						name += (Long) S57dat.getSubf(S57subf.RCID);
+						name <<= 16;
+						if (nflag == Nflag.ANON) {
+							map.newEdge(name);
+						}
+						break;
+					case VRPT:
+						S57dat.setField(record, fields + pos, S57field.VRPT, len);
+						do {
+							long conn = (Long) S57dat.getSubf(S57subf.NAME) << 16;
+							int topi = ((Long) S57dat.getSubf(S57subf.TOPI)).intValue();
+							map.addConn(conn, topi);
+							S57dat.getSubf(S57subf.MASK);
+						} while (S57dat.more());
+						break;
+					case SG2D:
+						S57dat.setField(record, fields + pos, S57field.SG2D, len);
+						do {
+							double lat = (double) ((Long) S57dat.getSubf(S57subf.YCOO)) / comf;
+							double lon = (double) ((Long) S57dat.getSubf(S57subf.XCOO)) / comf;
+							if (nflag == Nflag.ANON) {
+								map.newNode(++name, lat, lon, nflag);
+							} else {
+								map.newNode(name, lat, lon, nflag);
+							}
+							if (lat < bounds.minlat)
+								bounds.minlat = lat;
+							if (lat > bounds.maxlat)
+								bounds.maxlat = lat;
+							if (lon < bounds.minlon)
+								bounds.minlon = lon;
+							if (lon > bounds.maxlon)
+								bounds.maxlon = lon;
+						} while (S57dat.more());
+						break;
+					case SG3D:
+						S57dat.setField(record, fields + pos, S57field.SG3D, len);
+						do {
+							double lat = (double) ((Long) S57dat.getSubf(S57subf.YCOO)) / comf;
+							double lon = (double) ((Long) S57dat.getSubf(S57subf.XCOO)) / comf;
+							double depth = (double) ((Long) S57dat.getSubf(S57subf.VE3D)) / somf;
+							map.newNode(name++, lat, lon, depth);
+							if (lat < bounds.minlat)
+								bounds.minlat = lat;
+							if (lat > bounds.maxlat)
+								bounds.maxlat = lat;
+							if (lon < bounds.minlon)
+								bounds.minlon = lon;
+							if (lon > bounds.maxlon)
+								bounds.maxlon = lon;
+						} while (S57dat.more());
+						break;
+					default:
+						break;
+					}
+				}
+				if (inFeature) {
+					map.endFeature();
+					inFeature = false;
+				}
+			}
+		}
+		map.endFile();
+		in.close();
+		
+		return bounds;
+	}
+	
+}
Index: /applications/editors/josm/plugins/smed2/src/s57/S57map.java
===================================================================
--- /applications/editors/josm/plugins/smed2/src/s57/S57map.java	(revision 30283)
+++ /applications/editors/josm/plugins/smed2/src/s57/S57map.java	(revision 30284)
@@ -20,4 +20,17 @@
 
 public class S57map {
+	
+	public class MapBounds {
+		public double minlat;
+		public double minlon;
+		public double maxlat;
+		public double maxlon;
+		public MapBounds() {
+			minlat = 90;
+			minlon = 180;
+			maxlat = -90;
+			maxlon = -180;
+		}
+	}
 
 	public enum Nflag {
@@ -526,4 +539,135 @@
 	// Utility methods
 	
+	public void sortGeom() {
+		for (long id : index.keySet()) {
+			feature = index.get(id);
+			Geom sort = new Geom(feature.geom.prim);
+			long first = 0;
+			long last = 0;
+			Comp comp = null;
+			boolean next = true;
+			if ((feature.geom.prim == Pflag.LINE) || (feature.geom.prim == Pflag.AREA)) {
+				int sweep = feature.geom.elems.size();
+				while (!feature.geom.elems.isEmpty()) {
+					Prim prim = feature.geom.elems.remove(0);
+					Edge edge = edges.get(prim.id);
+					if (next == true) {
+						next = false;
+						if (prim.forward) {
+							first = edge.first;
+							last = edge.last;
+						} else {
+							first = edge.last;
+							last = edge.first;
+						}
+						sort.elems.add(prim);
+						if (prim.outer) {
+							sort.outers++;
+						} else {
+							sort.inners++;
+						}
+						comp = new Comp(ref++, 1);
+						sort.refs.add(comp);
+					} else {
+						if (prim.forward) {
+							if (edge.first == last) {
+								sort.elems.add(prim);
+								last = edge.last;
+								comp.size++;
+							} else if (edge.last == first) {
+								sort.elems.add(0, prim);
+								first = edge.first;
+								comp.size++;
+							} else {
+								feature.geom.elems.add(prim);
+							}
+						} else {
+							if (edge.last == last) {
+								sort.elems.add(prim);
+								last = edge.first;
+								comp.size++;
+							} else if (edge.first == first) {
+								sort.elems.add(0, prim);
+								first = edge.last;
+								comp.size++;
+							} else {
+								feature.geom.elems.add(prim);
+							}
+						}
+					}
+					if (--sweep == 0) {
+						next = true;
+						sweep = feature.geom.elems.size();
+					}
+				}
+				if ((sort.prim == Pflag.LINE) && (sort.outers == 1) && (sort.inners == 0) && (first == last)) {
+					sort.prim = Pflag.AREA;
+				}
+				feature.geom = sort;
+			} 
+			if (feature.geom.prim == Pflag.AREA) {
+				ArrayList<Prim> outers = new ArrayList<Prim>();
+				ArrayList<Prim> inners = new ArrayList<Prim>();
+				for (Prim prim : feature.geom.elems) {
+					if (prim.outer) {
+						outers.add(prim);
+					} else {
+						inners.add(prim);
+					}
+				}
+				ArrayList<Prim> sorting = outers;
+				ArrayList<Prim> closed = null;
+				sort = new Geom(feature.geom.prim);
+				sort.outers = feature.geom.outers;
+				sort.inners = feature.geom.inners;
+				sort.refs = feature.geom.refs;
+				next = true;
+				while (!sorting.isEmpty()) {
+					Prim prim = sorting.remove(0);
+					Edge edge = edges.get(prim.id);
+					if (next == true) {
+						next = false;
+						closed = new ArrayList<Prim>();
+						closed.add(prim);
+						if (prim.forward) {
+							first = edge.first;
+							last = edge.last;
+						} else {
+							first = edge.last;
+							last = edge.first;
+						}
+					} else {
+						if (prim.forward) {
+							if (edge.first == last) {
+								last = edge.last;
+								closed.add(prim);
+							} else {
+								sorting.add(0, prim);
+								next = true;
+							}
+						} else {
+							if (edge.last == last) {
+								last = edge.first;
+								closed.add(prim);
+							} else {
+								sorting.add(0, prim);
+								next = true;
+							}
+						}
+					}
+					if (first == last) {
+						sort.elems.addAll(closed);
+						next = true;
+					}
+					if (sorting.isEmpty() && sorting == outers) {
+						sorting = inners;
+						next = true;
+					}
+				}
+				feature.geom = sort;
+			}
+		}
+	}
+	
 	public boolean cmpGeoms (Geom g1, Geom g2) {
 		return ((g1.prim == g2.prim) && (g1.outers == g2.outers) && (g1.inners == g2.inners) && (g1.elems.size() == g2.elems.size()));
