Revision: 628
Author: allain.lalonde
Date: Thu Jul 30 12:36:17 2009
Log: FingBugs Hunting.
http://code.google.com/p/piccolo2d/source/detail?r=628
Added:
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/MockPCamera.java
Modified:
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/PCamera.java
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/activities/PTransformActivity.java
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/nodes/PImage.java
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/util/PUtil.java
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/PCanvasTest.java
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/PLayerTest.java
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/nodes/PImageTest.java
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/nodes/PPathTest.java
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/activities/PPathActivity.java
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/activities/PPositionPathActivity.java
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/event/PNavigationEventHandler.java
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/nodes/PStyledText.java
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollPaneLayout.java
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/swing/PViewport.java
/piccolo2d.java/trunk/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingCanvasTest.java
=======================================
--- /dev/null
+++
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/MockPCamera.java
Thu Jul 30 12:36:17 2009
@@ -0,0 +1,49 @@
+/**
+ *
+ */
+package edu.umd.cs.piccolo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import edu.umd.cs.piccolo.util.PBounds;
+
+class MockPCamera extends PCamera {
+ private static final long serialVersionUID = 1L;
+ private List notifications = new ArrayList();
+
+ public void repaintFromLayer(final PBounds bounds, final PLayer layer)
{
+ notifications.add(new Notification("repaintFromLayer", bounds,
layer));
+ super.repaintFromLayer(bounds, layer);
+ }
+
+ static class Notification {
+ private final String type;
+ private final PBounds bounds;
+ // this should really be PLayer
+ private final PNode layer;
+
+ private Notification(final String type, final PBounds bounds,
final PNode layer) {
+ this.bounds = bounds;
+ this.layer = layer;
+ this.type = type;
+ }
+
+ public PNode getLayer() {
+ return layer;
+ }
+
+ public PBounds getBounds() {
+ return bounds;
+ }
+ }
+
+ public int getNotificationCount() {
+ return notifications.size();
+ }
+
+ public Notification getNotification(int i) {
+ return (Notification)notifications.get(i);
+ }
+
+}
=======================================
---
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/PCamera.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/PCamera.java
Thu Jul 30 12:36:17 2009
@@ -174,7 +174,11 @@
* modify the viewBounds parameter.
*/
public void repaintFromLayer(final PBounds viewBounds, final PNode
repaintedLayer) {
- this.repaintFromLayer(viewBounds, (PLayer) repaintedLayer);
+ if (repaintedLayer instanceof PLayer) {
+ this.repaintFromLayer(viewBounds, (PLayer) repaintedLayer);
+ } else {
+ throw new RuntimeException("Passed non PLayer node to
repaintFromLayer");
+ }
}
// ****************************************************************
=======================================
---
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/activities/PTransformActivity.java
Tue Jul 28 13:58:25 2009
+++
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/activities/PTransformActivity.java
Thu Jul 30 12:36:17 2009
@@ -31,6 +31,7 @@
import java.awt.geom.AffineTransform;
import edu.umd.cs.piccolo.util.PAffineTransform;
+import edu.umd.cs.piccolo.util.PUtil;
/**
* <b>PTransformActivity</b> interpolates between two transforms setting
its
@@ -111,7 +112,7 @@
* target when the transform activity stops stepping.
*/
public double[] getDestinationTransform() {
- return destination;
+ return (destination == null) ? null : (double[])
destination.clone();
}
/**
@@ -119,7 +120,7 @@
* target when the transform activity stops stepping.
*/
public void setDestinationTransform(final double[] newDestination) {
- destination = newDestination;
+ destination = (newDestination == null) ? null : (double[])
newDestination.clone();
}
protected void activityStarted() {
=======================================
---
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/nodes/PImage.java
Tue Jul 28 13:58:25 2009
+++
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/nodes/PImage.java
Thu Jul 30 12:36:17 2009
@@ -128,31 +128,13 @@
* load the image using a MediaTracker before returning.
*/
public void setImage(final Image newImage) {
- final Image old = image;
+ final Image oldImage = image;
if (newImage == null || newImage instanceof BufferedImage) {
image = newImage;
}
- else { // else make sure the image is loaded
- final ImageIcon imageLoader = new ImageIcon(newImage);
- switch (imageLoader.getImageLoadStatus()) {
- case MediaTracker.LOADING:
- System.err.println("media tracker still loading image
after requested to wait until finished");
-
- case MediaTracker.COMPLETE:
- image = imageLoader.getImage();
- break;
-
- case MediaTracker.ABORTED:
- System.err.println("media tracker aborted image load");
- image = null;
- break;
-
- case MediaTracker.ERRORED:
- System.err.println("media tracker errored image load");
- image = null;
- break;
- }
+ else {
+ image = getLoadedImage(newImage);
}
if (image != null) {
@@ -160,7 +142,25 @@
invalidatePaint();
}
- firePropertyChange(PROPERTY_CODE_IMAGE, PROPERTY_IMAGE, old,
image);
+ firePropertyChange(PROPERTY_CODE_IMAGE, PROPERTY_IMAGE, oldImage,
image);
+ }
+
+ /**
+ * Ensures the image is loaded enough (loading is fine)
+ *
+ * @param newImage to check
+ * @return image or null if not loaded enough.
+ */
+ private Image getLoadedImage(final Image newImage) {
+ final ImageIcon imageLoader = new ImageIcon(newImage);
+ switch (imageLoader.getImageLoadStatus()) {
+ case MediaTracker.LOADING:
+ return imageLoader.getImage();
+ case MediaTracker.COMPLETE:
+ return imageLoader.getImage();
+ default:
+ return null;
+ }
}
protected void paint(final PPaintContext paintContext) {
=======================================
---
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/util/PUtil.java
Thu Jul 30 02:01:10 2009
+++
/piccolo2d.java/trunk/core/src/main/java/edu/umd/cs/piccolo/util/PUtil.java
Thu Jul 30 12:36:17 2009
@@ -56,7 +56,7 @@
public static long DEFAULT_ACTIVITY_STEP_RATE = 20;
public static int ACTIVITY_SCHEDULER_FRAME_DELAY = 10;
- private static final int PATH_IS_DONE = -1;
+ private static final int PATH_TERMINATOR = -1;
public static Iterator NULL_ITERATOR =
Collections.EMPTY_LIST.iterator();
public static Enumeration NULL_ENUMERATION = new Enumeration() {
@@ -197,7 +197,7 @@
path.closePath();
break;
- case PATH_IS_DONE:
+ case PATH_TERMINATOR:
return path;
default:
@@ -253,6 +253,6 @@
i.next();
}
- out.writeInt(PATH_IS_DONE);
- }
-}
+ out.writeInt(PATH_TERMINATOR);
+ }
+}
=======================================
---
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/PCanvasTest.java
Tue Jul 28 13:41:36 2009
+++
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/PCanvasTest.java
Thu Jul 30 12:36:17 2009
@@ -2,20 +2,16 @@
import java.awt.Cursor;
-import javax.swing.JPanel;
-
import junit.framework.TestCase;
import edu.umd.cs.piccolo.event.PInputEventListener;
import edu.umd.cs.piccolo.util.PBounds;
import edu.umd.cs.piccolo.util.PPaintContext;
public class PCanvasTest extends TestCase {
- private PCanvas canvas;
- private int pCanvasFinalizerCount;
+ private PCanvas canvas;
private MockPInputEventListener mockListener;
- public void setUp() {
- pCanvasFinalizerCount = 0;
+ public void setUp() {
canvas = new PCanvas();
mockListener = new MockPInputEventListener();
}
@@ -105,7 +101,7 @@
canvas.addInputEventListener(mockListener);
final PInputEventListener[] listeners =
canvas.getInputEventListeners();
assertNotNull(listeners);
- assertEquals(3, listeners.length); // 3 since pan and zoom are
attached
+ assertEquals(3, listeners.length); // zoom + pan + mockListener
// by default
}
@@ -114,34 +110,6 @@
canvas.removeInputEventListener(mockListener);
final PInputEventListener[] listeners =
canvas.getInputEventListeners();
assertNotNull(listeners);
- assertEquals(2, listeners.length); // 3 since pan and zoom are
attached
- // by default
- }
-
- public void testMemoryLeak() throws InterruptedException {
- final JPanel panel = new JPanel();
- for (int i = 0; i < 10; i++) {
- PCanvas canvas = new PCanvas() {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- public void finalize() {
- pCanvasFinalizerCount++;
- }
- };
- panel.add(canvas);
- panel.remove(canvas);
- canvas = null;
- }
- System.gc();
- System.runFinalization();
- PCanvas.CURRENT_ZCANVAS = null;
-
- // Not sure why I need -1 here, but I do. If I create 10000 it'll
always
- // be 1 less
- // assertEquals(10-1, pCanvasFinalizerCount);
- }
-
-}
+ assertEquals(2, listeners.length); // zoom + pan + mockListener
+ }
+}
=======================================
---
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/PLayerTest.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/PLayerTest.java
Thu Jul 30 12:36:17 2009
@@ -1,8 +1,6 @@
package edu.umd.cs.piccolo;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
import junit.framework.TestCase;
import edu.umd.cs.piccolo.util.PBounds;
@@ -96,37 +94,10 @@
final PBounds bounds = new PBounds(0, 0, 100, 100);
layer.repaintFrom(bounds, layer);
- assertEquals(1, camera.notifications.size());
-
- final MockPCamera.Notification notification =
(MockPCamera.Notification) camera.notifications.get(0);
- assertEquals(layer, notification.layer);
- assertEquals(bounds, notification.bounds);
- }
-
- static class MockPCamera extends PCamera {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- List notifications = new ArrayList();
-
- public void repaintFromLayer(final PBounds bounds, final PLayer
layer) {
- notifications.add(new Notification("repaintFromLayer", bounds,
layer));
- super.repaintFromLayer(bounds, layer);
- }
-
- class Notification {
- String type;
- PBounds bounds;
- // this should really be PLayer
- PNode layer;
-
- Notification(final String type, final PBounds bounds, final
PNode layer) {
- this.bounds = bounds;
- this.layer = layer;
- this.type = type;
- }
- }
-
+ assertEquals(1, camera.getNotificationCount());
+
+ final MockPCamera.Notification notification =
(MockPCamera.Notification) camera.getNotification(0);
+ assertEquals(layer, notification.getLayer());
+ assertEquals(bounds, notification.getBounds());
}
}
=======================================
---
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/nodes/PImageTest.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/nodes/PImageTest.java
Thu Jul 30 12:36:17 2009
@@ -63,11 +63,11 @@
public void testCanBeCreatedFromFile() throws IOException {
final BufferedImage img = new BufferedImage(100, 100,
BufferedImage.TYPE_INT_RGB);
- final File imgFile = File.createTempFile("test", ".jpeg");
- imgFile.deleteOnExit();
+ final File imgFile = File.createTempFile("test", ".jpeg");
ImageIO.write(img, "JPEG", imgFile);
-
+ imgFile.deleteOnExit();
final PImage imageNode = new PImage(imgFile.getAbsolutePath());
+ assertNotNull(imageNode.getImage());
assertEquals(100, imageNode.getImage().getWidth(null));
assertEquals(100, imageNode.getImage().getHeight(null));
}
=======================================
---
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/nodes/PPathTest.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/core/src/test/java/edu/umd/cs/piccolo/nodes/PPathTest.java
Thu Jul 30 12:36:17 2009
@@ -76,9 +76,9 @@
final File file = File.createTempFile("test", "ser");
serializeToFile(srcPath, file);
-
- final PPath resultPath = deserializeFromFile(srcBounds, file);
-
+ final PPath resultPath = deserializeFromFile(srcBounds, file);
+ file.deleteOnExit();
+
assertEquals(resultPath.getBounds(), srcBounds);
}
@@ -87,8 +87,7 @@
PPath path;
final FileInputStream fin = new FileInputStream(file);
final ObjectInputStream in = new ObjectInputStream(fin);
- path = (PPath) in.readObject();
- file.delete();
+ path = (PPath) in.readObject();
return path;
}
=======================================
---
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/activities/PPathActivity.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/activities/PPathActivity.java
Thu Jul 30 12:36:17 2009
@@ -29,6 +29,7 @@
package edu.umd.cs.piccolox.activities;
import edu.umd.cs.piccolo.activities.PInterpolatingActivity;
+import edu.umd.cs.piccolo.util.PUtil;
/**
* <b>PPathActivity</b> is the abstract base class for all path activity
@@ -67,12 +68,12 @@
return knots.length;
}
- public void setKnots(final float[] knots) {
- this.knots = knots;
+ public void setKnots(final float[] newKnots) {
+ this.knots = (newKnots == null) ? newKnots : (float[])
newKnots.clone();
}
public float[] getKnots() {
- return knots;
+ return (knots == null) ? knots : (float[]) knots.clone();
}
public void setKnot(final int index, final float knot) {
=======================================
---
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/activities/PPositionPathActivity.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/activities/PPositionPathActivity.java
Thu Jul 30 12:36:17 2009
@@ -62,8 +62,8 @@
public PPositionPathActivity(final long duration, final long stepRate,
final int loopCount, final int mode,
final Target aTarget, final float[] knots, final Point2D[]
positions) {
super(duration, stepRate, loopCount, mode, knots);
- target = aTarget;
- this.positions = positions;
+ target = aTarget;
+ this.positions = (Point2D[])positions.clone();
}
protected boolean isAnimation() {
@@ -71,7 +71,7 @@
}
public Point2D[] getPositions() {
- return positions;
+ return (Point2D[])positions.clone();
}
public Point2D getPosition(final int index) {
@@ -79,7 +79,7 @@
}
public void setPositions(final Point2D[] positions) {
- this.positions = positions;
+ this.positions = (Point2D[])positions.clone();
}
public void setPosition(final int index, final Point2D position) {
=======================================
---
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/event/PNavigationEventHandler.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/event/PNavigationEventHandler.java
Thu Jul 30 12:36:17 2009
@@ -326,7 +326,7 @@
final double scaleFactor = d.getWidth() / aCamera.getViewScale();
final Point2D scalePoint =
focusNode.getGlobalFullBounds().getCenter2D();
- if (scaleFactor != 1) {
+ if (Math.abs(1f-scaleFactor) < 0.0001) {
aCamera.scaleViewAboutPoint(scaleFactor, scalePoint.getX(),
scalePoint.getY());
}
=======================================
---
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/nodes/PStyledText.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/nodes/PStyledText.java
Thu Jul 30 12:36:17 2009
@@ -297,10 +297,10 @@
font = style.getFont(((DefaultStyledDocument)
document).getCharacterElement(pos).getAttributes());
if (font == null) {
font = style.getFont(((DefaultStyledDocument)
document).getParagraphElement(pos).getAttributes());
- }
- if (font == null) {
- font = style.getFont(rootElement.getAttributes());
- }
+ if (font == null) {
+ font = style.getFont(rootElement.getAttributes());
+ }
+ }
}
else {
font = style.getFont(rootElement.getAttributes());
=======================================
---
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java
Thu Jul 30 12:36:17 2009
@@ -219,10 +219,10 @@
/**
* The cutoff at which the Swing component is rendered greek
*/
- private final double renderCutoff = 0.3;
+ private static final double GREEK_SCALE_CUT_OFF = 0.3d;
private JComponent component = null;
private double minFontSize = Double.MAX_VALUE;
- private Stroke defaultStroke = new BasicStroke();
+ private transient Stroke defaultStroke = new BasicStroke();
private Font defaultFont = new Font("Serif", Font.PLAIN, 12);
private PSwingCanvas canvas;
@@ -381,7 +381,7 @@
}
protected boolean shouldRenderGreek(final PPaintContext renderContext)
{
- return renderContext.getScale() < renderCutoff
+ return renderContext.getScale() < GREEK_SCALE_CUT_OFF
// && pSwingCanvas.getInteracting()
|| minFontSize * renderContext.getScale() < 0.5;
}
=======================================
---
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java
Thu Jul 30 12:36:17 2009
@@ -44,9 +44,6 @@
* @author Lance E. Good
*/
public class PSwingCanvas extends PCanvas {
- /**
- *
- */
private static final long serialVersionUID = 1L;
public static final String SWING_WRAPPER_KEY = "Swing Wrapper";
private final ChildWrapper swingWrapper;
@@ -62,14 +59,9 @@
}
private void initRepaintManager() {
- final RepaintManager repaintManager =
RepaintManager.currentManager(this);
- PSwingRepaintManager pSwingRepaintManager;
- if (repaintManager instanceof PSwingRepaintManager) {
- pSwingRepaintManager = (PSwingRepaintManager) repaintManager;
- }
- else {
- pSwingRepaintManager = new PSwingRepaintManager();
- RepaintManager.setCurrentManager(pSwingRepaintManager);
+ final RepaintManager repaintManager =
RepaintManager.currentManager(this);
+ if (!(repaintManager instanceof PSwingRepaintManager)) {
+ RepaintManager.setCurrentManager(new PSwingRepaintManager());
}
}
=======================================
---
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollPaneLayout.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollPaneLayout.java
Thu Jul 30 12:36:17 2009
@@ -66,6 +66,9 @@
/*
* Sync the (now obsolete) policy fields with the JScrollPane.
*/
+ if (!(parent instanceof JScrollPane)) {
+ throw new IllegalArgumentException("layoutContainer may only
be applied to JScrollPanes");
+ }
final JScrollPane scrollPane = (JScrollPane) parent;
vsbPolicy = scrollPane.getVerticalScrollBarPolicy();
hsbPolicy = scrollPane.getHorizontalScrollBarPolicy();
=======================================
---
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/swing/PViewport.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/extras/src/main/java/edu/umd/cs/piccolox/swing/PViewport.java
Thu Jul 30 12:36:17 2009
@@ -225,6 +225,9 @@
* @param parent the container to lay out
*/
public void layoutContainer(final Container parent) {
+ if (!(parent instanceof JViewport)) {
+ throw new
IllegalArgumentException("PViewport.layoutContainer may only be applied to
JViewports");
+ }
final JViewport vp = (JViewport) parent;
final Component view = vp.getView();
=======================================
---
/piccolo2d.java/trunk/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingCanvasTest.java
Tue Jul 28 12:46:54 2009
+++
/piccolo2d.java/trunk/extras/src/test/java/edu/umd/cs/piccolox/pswing/PSwingCanvasTest.java
Thu Jul 30 12:36:17 2009
@@ -28,7 +28,7 @@
*/
package edu.umd.cs.piccolox.pswing;
-import javax.swing.JPanel;
+import javax.swing.JLabel;
import junit.framework.TestCase;
@@ -40,33 +40,11 @@
public void setUp() {
finalizerCallCount = 0;
- }
-
- public void testMemoryLeak() throws InterruptedException {
- JPanel panel = new JPanel();
- for (int i = 0; i < 10; i++) {
- PSwingCanvas canvas = new PSwingCanvas() {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
-
- public void finalize() {
- finalizerCallCount++;
- }
- };
- panel.add(canvas);
- panel.remove(canvas);
- canvas = null;
- }
- panel = null;
- System.gc();
- System.runFinalization();
-
- // Not sure why I need -1 here, but I do. If I create 10000 it'll
always
- // be 1 less
- // TODO: make this work in all environments. Will not work at the
- // command line for some.
- // assertEquals(10 - 1, finalizerCallCount);
+ }
+
+ public void testRemovePSwingDoesNothingWithForeignPSwing() {
+ PSwingCanvas canvas = new PSwingCanvas();
+ PSwing orphanPSwing = new PSwing(new JLabel());
+ canvas.removePSwing(orphanPSwing);
}
}
--~--~---------~--~----~------------~-------~--~----~
Piccolo2D Developers Group: http://groups.google.com/group/piccolo2d-dev?hl=en
-~----------~----~----~----~------~----~------~--~---