diff --git a/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java b/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java index a79b5a7a2..e74c842c2 100644 --- a/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java +++ b/src/java/com/threerings/miso/client/DisplayMisoSceneImpl.java @@ -1,5 +1,5 @@ // -// $Id: DisplayMisoSceneImpl.java,v 1.19 2001/08/09 21:17:06 shaper Exp $ +// $Id: DisplayMisoSceneImpl.java,v 1.20 2001/08/10 00:47:34 shaper Exp $ package com.threerings.miso.scene; @@ -8,6 +8,7 @@ import java.io.*; import java.util.ArrayList; import com.samskivert.util.StringUtil; +import com.threerings.miso.Log; import com.threerings.miso.tile.Tile; import com.threerings.miso.tile.TileManager; @@ -22,7 +23,7 @@ public class Scene /** The base layer id. */ public static final int LAYER_BASE = 0; - /** The object layer id. */ + /** The fringe layer id. */ public static final int LAYER_FRINGE = 1; /** The object layer id. */ @@ -65,9 +66,10 @@ public class Scene _sid = SID_INVALID; _name = DEF_SCENE_NAME; _locations = new ArrayList(); + _spots = new SpotGroup(); _exits = new ArrayList(); - tiles = new Tile[TILE_WIDTH][TILE_HEIGHT][NUM_LAYERS]; + tiles = new Tile[TILE_WIDTH][TILE_HEIGHT][NUM_LAYERS]; _deftile = _tilemgr.getTile(deftsid, deftid); for (int xx = 0; xx < TILE_WIDTH; xx++) { for (int yy = 0; yy < TILE_HEIGHT; yy++) { @@ -90,17 +92,47 @@ public class Scene * @param tiles the tiles comprising the scene. */ public Scene (TileManager tilemgr, String name, - ArrayList locations, ArrayList exits, + ArrayList locations, ArrayList spots, ArrayList exits, Tile tiles[][][]) { _tilemgr = tilemgr; _sid = SID_INVALID; _name = name; _locations = locations; + _spots = new SpotGroup(spots); _exits = exits; this.tiles = tiles; } + public void updateLocation (int x, int y, int orient, int spotidx) + { + Log.info("updateLocation [x=" + x + ", y=" + y + + ", orient=" + orient + ", spotidx=" + spotidx + "]."); + + // look the location up in our existing location list + int size = _locations.size(); + Location loc = null; + for (int ii = 0; ii < size; ii++) { + Location tloc = (Location)_locations.get(ii); + + if (tloc.x == x && tloc.y == y) { + // if we found it, update the location information + tloc.x = x; + tloc.y = y; + tloc.orient = orient; + + // and update the spot contents + _spots.respot(tloc, spotidx); + + return; + } + } + + // else we didn't find a location object, so create one + _locations.add(loc = new Location(x, y, orient)); + _spots.respot(loc, spotidx); +} + /** * Return the scene name. */ @@ -125,6 +157,14 @@ public class Scene return _locations; } + /** + * Return the spot group. + */ + public SpotGroup getSpotGroup () + { + return _spots; + } + /** * Return the scene exits list. */ @@ -133,6 +173,11 @@ public class Scene return _exits; } + public int getNumSpots () + { + return _spots.size(); + } + /** * Return the number of actual (non-null) tiles present in the * specified tile layer for this scene. @@ -170,6 +215,7 @@ public class Scene buf.append(", sid=").append(_sid); buf.append(", locations=").append(StringUtil.toString(_locations)); buf.append(", exits=").append(StringUtil.toString(_exits)); + buf.append(", spots=").append(StringUtil.toString(_spots)); return buf.append("]").toString(); } @@ -185,9 +231,12 @@ public class Scene /** The locations within the scene. */ protected ArrayList _locations; - /** The exit points to different scenes. */ + /** The exits to different scenes. */ protected ArrayList _exits; + /** The spots within the scene. */ + protected SpotGroup _spots; + /** The default tile for the base layer in the scene. */ protected Tile _deftile; diff --git a/src/java/com/threerings/miso/client/IsoSceneView.java b/src/java/com/threerings/miso/client/IsoSceneView.java index e09eb1430..9c13254c9 100644 --- a/src/java/com/threerings/miso/client/IsoSceneView.java +++ b/src/java/com/threerings/miso/client/IsoSceneView.java @@ -1,5 +1,5 @@ // -// $Id: IsoSceneView.java,v 1.35 2001/08/09 21:17:06 shaper Exp $ +// $Id: IsoSceneView.java,v 1.36 2001/08/10 00:47:34 shaper Exp $ package com.threerings.miso.scene; @@ -501,6 +501,16 @@ public class IsoSceneView implements EditableSceneView return path; } + public void updateLocation (int x, int y, int orient, int spotidx) + { + _scene.updateLocation(x, y, orient, spotidx); + } + + public int getNumSpots () + { + return (_scene == null) ? 0 : _scene.getNumSpots(); + } + /** The color to draw the highlighted tile. */ protected static final Color HLT_COLOR = Color.green; diff --git a/src/java/com/threerings/miso/client/Location.java b/src/java/com/threerings/miso/client/Location.java index 76282c39d..895695fb2 100644 --- a/src/java/com/threerings/miso/client/Location.java +++ b/src/java/com/threerings/miso/client/Location.java @@ -1,5 +1,5 @@ // -// $Id: Location.java,v 1.1 2001/08/09 21:17:06 shaper Exp $ +// $Id: Location.java,v 1.2 2001/08/10 00:47:34 shaper Exp $ package com.threerings.miso.scene; @@ -13,9 +13,6 @@ package com.threerings.miso.scene; */ public class Location { - /** The spot index in the scene containing this location. */ - public int spotid; - /** The location position in full coordinates. */ public int x, y; @@ -25,14 +22,12 @@ public class Location /** * Construct a Location object. * - * @param spotid the spot id. * @param x the x-position full coordinate. * @param y the y-position full coordinate. * @param orient the location orientation. */ - public Location (int spotid, int x, int y, int orient) + public Location (int x, int y, int orient) { - this.spotid = spotid; this.x = x; this.y = y; this.orient = orient; @@ -44,8 +39,7 @@ public class Location public String toString () { StringBuffer buf = new StringBuffer(); - buf.append("[spotid=").append(spotid); - buf.append(", x=").append(x); + buf.append("[x=").append(x); buf.append(", y=").append(y); buf.append(", orient=").append(orient); return buf.append("]").toString(); diff --git a/src/java/com/threerings/miso/client/Spot.java b/src/java/com/threerings/miso/client/Spot.java new file mode 100644 index 000000000..874563ef4 --- /dev/null +++ b/src/java/com/threerings/miso/client/Spot.java @@ -0,0 +1,77 @@ +// +// $Id: Spot.java,v 1.1 2001/08/10 00:47:34 shaper Exp $ + +package com.threerings.miso.scene; + +import java.util.ArrayList; + +/** + * A Spot is a gathering of Location objects + * that represent a logical grouping for the purposes of display and + * interaction in a scene. + * + *

This class is currently just a wrapper around an + * ArrayList, but the theory is that we may soon want + * more useful functionality encapsulated herein, and the + * Spot nomenclature is useful in any case. + */ +public class Spot +{ + /** + * Construct a Spot object. + */ + public Spot () + { + _locations = new ArrayList(); + } + + /** + * Add a location to the spot. + * + * @param loc the location. + */ + public void add (Location loc) + { + _locations.add(loc); + } + + /** + * Return whether the spot contains the given location. + * + * @param loc the location. + */ + public boolean contains (Location loc) + { + return _locations.contains(loc); + } + + /** + * Removes the location from the spot if present, and returns true + * if the location was present, false if not. + * + * @param loc the location. + */ + public boolean remove (Location loc) + { + return _locations.remove(loc); + } + + /** + * Return the number of locations in the spot. + */ + public int size () + { + return _locations.size(); + } + + /** + * Return the list of locations that the spot is made up of. + */ + public ArrayList getLocations () + { + return _locations; + } + + /** The list of locations in this spot. */ + protected ArrayList _locations; +} diff --git a/src/java/com/threerings/miso/client/SpotGroup.java b/src/java/com/threerings/miso/client/SpotGroup.java new file mode 100644 index 000000000..8b8881d4a --- /dev/null +++ b/src/java/com/threerings/miso/client/SpotGroup.java @@ -0,0 +1,141 @@ +// +// $Id: SpotGroup.java,v 1.1 2001/08/10 00:47:34 shaper Exp $ + +package com.threerings.miso.scene; + +import java.util.ArrayList; + +import com.threerings.miso.Log; + +/** + * The SpotGroup class manages all of the + * Spot objects associated with a scene. The scene should + * only interact with spots via the SpotGroup class. + */ +public class SpotGroup +{ + /** + * Construct a SpotGroup object. + */ + public SpotGroup () + { + _spots = new ArrayList(); + } + + /** + * Construct a SpotGroup object, initializing it to + * contain the given list of Spot objects. + * + * @param list the list of spots. + */ + public SpotGroup (ArrayList spots) + { + _spots = spots; + } + + /** + * Return the list of Spot objects contained in the group. + */ + public ArrayList getSpots () + { + return _spots; + } + + /** + * Remove the given location from its spot, if any. + * + * @param loc the location. + */ + public void remove (Location loc) + { + int size = _spots.size(); + for (int ii = 0; ii < size; ii++) { + Spot spot = (Spot)_spots.get(ii); + + if (spot.contains(loc)) { + spot.remove(loc); + + // remove the spot itself if it contains no more locations + if (spot.size() == 0) { + _spots.remove(spot); + } + + // we know the location can only reside in at most one spot + break; + } + } + } + + /** + * Re-spot the given location to be placed within the given spot + * index. + * + *

If the spot index is -1, the location is simply removed + * from any spot it may reside in. Otherwise, the location is + * removed from any location it may already be in, and placed in + * the spot corresponding to the requested spot index. + * + *

The spot index may be equal to the current number of spots + * in the group, in which case a new spot object will be created + * that initially contains only the given location. + * + * @param loc the location. + * @param spotidx the spot index, or -1 to remove the location + * from any containing spot. + */ + public void respot (Location loc, int spotidx) + { + // just remove the location if spotidx is -1 + if (spotidx == -1) { + remove(loc); + return; + } + + // make sure we're okay with the requested spot index + int size = _spots.size(); + if (spotidx > size) { + Log.warning("Attempt to respot location to a non-contiguous " + + "spot index [loc=" + loc + ", spotidx=" + + spotidx + "]."); + return; + } + + // get the spot object the location's to be placed in + Spot spot = null; + if (spotidx == size) { + // the location's being added to a new spot, so create it + _spots.add(spot = new Spot()); + + } else { + // retrieve the spot we're planning to place the location in + spot = (Spot)_spots.get(spotidx); + + // this should never happen, but sanity-check anyway + if (spot == null) { + Log.warning("Failed to retrieve spot [spotidx=" + + spotidx + "]."); + return; + } + + // bail if the spot already contains the location + if (spot.contains(loc)) return; + } + + // remove the location from any other spot it may already be in + remove(loc); + + // add the location to the spot + spot.add(loc); + } + + /** + * Return the number of spots in the group. + */ + public int size () + { + return _spots.size(); + } + + /** The list of spots in the spot group. */ + protected ArrayList _spots; +} diff --git a/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java b/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java index 596066f74..e6a42c58f 100644 --- a/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java +++ b/src/java/com/threerings/miso/tools/xml/XMLSceneParser.java @@ -1,5 +1,5 @@ // -// $Id: XMLSceneParser.java,v 1.6 2001/08/09 21:17:06 shaper Exp $ +// $Id: XMLSceneParser.java,v 1.7 2001/08/10 00:47:34 shaper Exp $ package com.threerings.miso.scene.xml; @@ -70,6 +70,10 @@ public class XMLSceneParser extends DefaultHandler int vals[] = StringUtil.parseIntArray(_chars.toString()); _scLocations = toLocationsList(vals); + } else if (qName.equals("spot")) { + int vals[] = StringUtil.parseIntArray(_chars.toString()); + _scSpots.add(toSpot(_scLocations, vals)); + } else if (qName.equals("exits")) { String vals[] = StringUtil.parseStringArray(_chars.toString()); _scExits = toExitList(_scLocations, vals); @@ -84,7 +88,7 @@ public class XMLSceneParser extends DefaultHandler } else if (qName.equals("scene")) { // construct the scene object on tag close _scene = new Scene( - _tilemgr, _scName, _scLocations, _scExits, _scTiles); + _tilemgr, _scName, _scLocations, _scSpots, _scExits, _scTiles); Log.info("Constructed parsed scene [scene=" + _scene + "]."); } @@ -163,11 +167,30 @@ public class XMLSceneParser extends DefaultHandler } } + /** + * Given an array of integer values, return a Spot + * object containing the location objects identified by location + * index number in the integer array. + * + * @param locs the locations list. + * @param vals the integer values. + * + * @return the spot object. + */ + protected Spot toSpot (ArrayList locs, int[] vals) + { + Spot spot = new Spot(); + for (int ii = 0; ii < vals.length; ii++) { + spot.add((Location)locs.get(vals[ii])); + } + return spot; + } + /** * Given an array of integer values, return a list of the * Location objects represented therein, constructed - * from each successive quartet of values as (spotid, x, y, - * orientation) in the integer array. + * from each successive triplet of values as (x, y, orientation) + * in the integer array. * * @param vals the integer values. * @@ -176,13 +199,13 @@ public class XMLSceneParser extends DefaultHandler protected ArrayList toLocationsList (int[] vals) { // make sure we have a seemingly-appropriate number of points - if ((vals.length % 4) != 0) return null; + if ((vals.length % 3) != 0) return null; // read in all of the locations and add to the list ArrayList list = new ArrayList(); - for (int ii = 0; ii < vals.length; ii += 4) { + for (int ii = 0; ii < vals.length; ii += 3) { Location loc = new Location( - vals[ii], vals[ii+1], vals[ii+2], vals[ii+3]); + vals[ii], vals[ii+1], vals[ii+2]); list.add(loc); } @@ -245,6 +268,7 @@ public class XMLSceneParser extends DefaultHandler _scTiles = new Tile[width][height][Scene.NUM_LAYERS]; _scLocations = null; _scExits = null; + _scSpots = new ArrayList(); } /** @@ -296,8 +320,7 @@ public class XMLSceneParser extends DefaultHandler // temporary storage of scene object values and data protected StringBuffer _chars; protected String _scName; - protected ArrayList _scLocations; - protected ArrayList _scExits; + protected ArrayList _scLocations, _scExits, _scSpots; protected Tile[][][] _scTiles; protected int _scLnum, _scRownum, _scColstart; } diff --git a/src/java/com/threerings/miso/tools/xml/XMLSceneWriter.java b/src/java/com/threerings/miso/tools/xml/XMLSceneWriter.java index 0f6e127ad..e644d3bad 100644 --- a/src/java/com/threerings/miso/tools/xml/XMLSceneWriter.java +++ b/src/java/com/threerings/miso/tools/xml/XMLSceneWriter.java @@ -1,5 +1,5 @@ // -// $Id: XMLSceneWriter.java,v 1.4 2001/08/09 21:17:06 shaper Exp $ +// $Id: XMLSceneWriter.java,v 1.5 2001/08/10 00:47:34 shaper Exp $ package com.threerings.miso.scene.xml; @@ -52,6 +52,11 @@ public class XMLSceneWriter extends DataWriter dataElement("name", scene.getName()); dataElement("version", "" + Scene.VERSION); dataElement("locations", getLocationData(scene)); + + startElement("spots"); + writeSpots(scene); + endElement("spots"); + dataElement("exits", getExitData(scene)); startElement("tiles"); @@ -70,6 +75,36 @@ public class XMLSceneWriter extends DataWriter } } + /** + * Output XML detailing the spot objects. Spots are described by + * a list of location object indexes that are contained within the + * spot. + * + * @param scene the scene object. + */ + protected void writeSpots (Scene scene) throws SAXException + { + ArrayList spots = scene.getSpotGroup().getSpots(); + ArrayList locs = scene.getLocations(); + + int size = spots.size(); + for (int ii = 0; ii < size; ii++) { + + StringBuffer buf = new StringBuffer(); + + Spot spot = (Spot)spots.get(ii); + ArrayList spotlocs = spot.getLocations(); + + int spotsize = spotlocs.size(); + for (int jj = 0; jj < spotsize; jj++) { + buf.append(locs.indexOf(spotlocs.get(jj))).append(","); + if (jj < spotsize - 1) buf.append(","); + } + + dataElement("spot", buf.toString()); + } + } + /** * Output XML detailing the tiles at the specified layer in the * given scene. The first layer is outputted in its entirety, @@ -137,7 +172,6 @@ public class XMLSceneWriter extends DataWriter int size = locs.size(); for (int ii = 0; ii < size; ii++) { Location loc = (Location)locs.get(ii); - buf.append(loc.spotid).append(","); buf.append(loc.x).append(","); buf.append(loc.y).append(","); buf.append(loc.orient); diff --git a/tests/rsrc/scenes/default.xml b/tests/rsrc/scenes/default.xml index 25b0b3f82..6b7824a98 100644 --- a/tests/rsrc/scenes/default.xml +++ b/tests/rsrc/scenes/default.xml @@ -4,29 +4,30 @@ Untitled Scene 1 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,6,1004,6,1004,6,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,6,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,6,1004,10,1004,10,1004,10,1004,10,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,6,1004,6,1004,6,1004,10,1004,10,1004,6,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,6,1004,6,1004,6,1004,6,1004,6,1004,6,1004,6,1004,6,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,8,1004,6,1004,6,1004,6,1004,6,1004,6,1004,6,1004,6,1004,3,1004,2,1004,6,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,8,1004,6,1004,6,1004,6,1004,6,1004,6,1004,6,1004,3,1004,2,1004,6,1004,6,1004,6,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,8,1004,6,1004,6,1004,6,1004,6,1004,6,1004,6,1004,11,1004,2,1004,6,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,8,1004,6,1004,6,1004,6,1004,6,1004,6,1004,6,1004,11,1004,1,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,8,1004,6,1004,6,1004,10,1004,6,1004,6,1004,6,1004,6,1004,6,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,9,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,6,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 - 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,6,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,0,1004,10,1004,10,1004,0,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 + 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,0,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10 1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10,1004,10