<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -9,31 +9,29 @@
 
 (function(){
 
-this.Processing = function Processing( aElement, aCode )
-{
+this.Processing = function Processing( aElement, aCode ) {
+  if ( typeof aElement == &quot;string&quot; )
+    aElement = document.getElementById( aElement );
+
   var p = buildProcessing( aElement );
-  p.init( aCode );
+
+  if ( aCode )
+    p.init( aCode );
+
   return p;
 };
 
-function log()
-{
-  try
-  {
+function log() {
+  try {
     console.log.apply( console, arguments );
-  }
-  catch(e)
-  {
-    try
-    {
+  } catch(e) {
+    try {
       opera.postError.apply( opera, arguments );
-    }
-    catch(e){}
+    } catch(e){}
   }
 }
 
-function parse( aCode, p )
-{
+var parse = Processing.parse = function parse( aCode, p ) {
   // Angels weep at this parsing code :-(
 
   // Remove end-of-line comments
@@ -43,14 +41,10 @@ function parse( aCode, p )
   aCode = aCode.replace(/([^\s])%([^\s])/g, &quot;$1 % $2&quot;);
  
   // Simple convert a function-like thing to function
-  aCode = aCode.replace(/(?:static )?(\w+ )(\w+)\s*(\([^\)]*\)\s*{)/g, function(all, type, name, args)
-  {
-    if ( name == &quot;if&quot; || name == &quot;for&quot; || name == &quot;while&quot; )
-    {
+  aCode = aCode.replace(/(?:static )?(\w+ )(\w+)\s*(\([^\)]*\)\s*{)/g, function(all, type, name, args) {
+    if ( name == &quot;if&quot; || name == &quot;for&quot; || name == &quot;while&quot; ) {
       return all;
-    }
-    else
-    {
+    } else {
       return &quot;Processing.&quot; + name + &quot; = function &quot; + name + args;
     }
   });
@@ -63,29 +57,24 @@ function parse( aCode, p )
   aCode = aCode.replace(/([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, &quot;$1$4&quot;);
 
   // float[] foo = new float[5];
-  aCode = aCode.replace(/new (\w+)((?:\[([^\]]*)\])+)/g, function(all, name, args)
-  {
+  aCode = aCode.replace(/new (\w+)((?:\[([^\]]*)\])+)/g, function(all, name, args) {
     return &quot;new ArrayList(&quot; + args.slice(1,-1).split(&quot;][&quot;).join(&quot;, &quot;) + &quot;)&quot;;
   });
   
-  aCode = aCode.replace(/(?:static )?\w+\[\]\s*(\w+)\[?\]?\s*=\s*{.*?};/g, function(all)
-  {
+  aCode = aCode.replace(/(?:static )?\w+\[\]\s*(\w+)\[?\]?\s*=\s*{.*?};/g, function(all) {
     return all.replace(/{/g, &quot;[&quot;).replace(/}/g, &quot;]&quot;);
   });
 
   // int|float foo;
   var intFloat = /(\n\s*(?:int|float)(?:\[\])?(?:\s*|[^\(]*?,\s*))([a-z]\w*)(;|,)/i;
-  while ( intFloat.test(aCode) )
-  {
-    aCode = aCode.replace(new RegExp(intFloat), function(all, type, name, sep)
-    {
+  while ( intFloat.test(aCode) ) {
+    aCode = aCode.replace(new RegExp(intFloat), function(all, type, name, sep) {
       return type + &quot; &quot; + name + &quot; = 0&quot; + sep;
     });
   }
 
   // float foo = 5;
-  aCode = aCode.replace(/(?:static )?(\w+)((?:\[\])+| ) *(\w+)\[?\]?(\s*[=,;])/g, function(all, type, arr, name, sep)
-  {
+  aCode = aCode.replace(/(?:static )?(\w+)((?:\[\])+| ) *(\w+)\[?\]?(\s*[=,;])/g, function(all, type, arr, name, sep) {
     if ( type == &quot;return&quot; )
       return all;
     else
@@ -93,14 +82,12 @@ function parse( aCode, p )
   });
 
   // Fix Array[] foo = {...} to [...]
-  aCode = aCode.replace(/=\s*{((.|\s)*?)};/g, function(all,data)
-  {
+  aCode = aCode.replace(/=\s*{((.|\s)*?)};/g, function(all,data) {
     return &quot;= [&quot; + data.replace(/{/g, &quot;[&quot;).replace(/}/g, &quot;]&quot;) + &quot;]&quot;;
   });
   
   // static { ... } blocks
-  aCode = aCode.replace(/static\s*{((.|\n)*?)}/g, function(all, init)
-  {
+  aCode = aCode.replace(/static\s*{((.|\n)*?)}/g, function(all, init) {
     // Convert the static definitons to variable assignments
     //return init.replace(/\((.*?)\)/g, &quot; = $1&quot;);
     return init;
@@ -111,14 +98,12 @@ function parse( aCode, p )
 
   var classes = [&quot;int&quot;, &quot;float&quot;, &quot;boolean&quot;, &quot;string&quot;];
 
-  function ClassReplace(all, name, extend, vars, last)
-  {
+  function ClassReplace(all, name, extend, vars, last) {
     classes.push( name );
 
     var static = &quot;&quot;;
 
-    vars = vars.replace(/final\s+var\s+(\w+\s*=\s*.*?;)/g, function(all,set)
-    {
+    vars = vars.replace(/final\s+var\s+(\w+\s*=\s*.*?;)/g, function(all,set) {
       static += &quot; &quot; + name + &quot;.&quot; + set;
       return &quot;&quot;;
     });
@@ -133,7 +118,7 @@ function parse( aCode, p )
         .replace(/,\s?/g, &quot;;\n  this.&quot;)
         .replace(/\b(var |final |public )+\s*/g, &quot;this.&quot;)
         .replace(/this.(\w+);/g, &quot;this.$1 = null;&quot;) + 
-	(extend ? &quot;extendClass(this, &quot; + extend + &quot;);\n&quot; : &quot;&quot;) +
+        (extend ? &quot;extendClass(this, &quot; + extend + &quot;);\n&quot; : &quot;&quot;) +
         &quot;&lt;CLASS &quot; + name + &quot; &quot; + static + &quot;&gt;&quot; + (typeof last == &quot;string&quot; ? last : name + &quot;(&quot;);
   }
 
@@ -145,8 +130,7 @@ function parse( aCode, p )
 
   var matchClass = /&lt;CLASS (\w+) (.*?)&gt;/, m;
   
-  while ( (m = aCode.match( matchClass )) )
-  {
+  while ( (m = aCode.match( matchClass )) ) {
     var left = RegExp.leftContext,
       allRest = RegExp.rightContext,
       rest = nextBrace(allRest),
@@ -155,8 +139,7 @@ function parse( aCode, p )
       
     allRest = allRest.slice( rest.length + 1 );
 
-    rest = rest.replace(new RegExp(&quot;\\b&quot; + className + &quot;\\(([^\\)]*?)\\)\\s*{&quot;, &quot;g&quot;), function(all, args)
-    {
+    rest = rest.replace(new RegExp(&quot;\\b&quot; + className + &quot;\\(([^\\)]*?)\\)\\s*{&quot;, &quot;g&quot;), function(all, args) {
       args = args.split(/,\s*?/);
       
       if ( args[0].match(/^\s*$/) )
@@ -164,8 +147,7 @@ function parse( aCode, p )
       
       var fn = &quot;if ( arguments.length == &quot; + args.length + &quot; ) {\n&quot;;
         
-      for ( var i = 0; i &lt; args.length; i++ )
-      {
+      for ( var i = 0; i &lt; args.length; i++ ) {
         fn += &quot;    var &quot; + args[i] + &quot; = arguments[&quot; + i + &quot;];\n&quot;;
       }
         
@@ -175,16 +157,14 @@ function parse( aCode, p )
     // Fix class method names
     // this.collide = function() { ... }
     // and add closing } for with(this) ...
-    rest = rest.replace(/(?:public )?Processing.\w+ = function (\w+)\((.*?)\)/g, function(all, name, args)
-    {
+    rest = rest.replace(/(?:public )?Processing.\w+ = function (\w+)\((.*?)\)/g, function(all, name, args) {
       return &quot;ADDMETHOD(this, '&quot; + name + &quot;', function(&quot; + args + &quot;)&quot;;
     });
     
     var matchMethod = /ADDMETHOD([\s\S]*?{)/, mc;
     var methods = &quot;&quot;;
     
-    while ( (mc = rest.match( matchMethod )) )
-    {
+    while ( (mc = rest.match( matchMethod )) ) {
       var prev = RegExp.leftContext,
         allNext = RegExp.rightContext,
         next = nextBrace(allNext);
@@ -192,7 +172,6 @@ function parse( aCode, p )
       methods += &quot;addMethod&quot; + mc[1] + next + &quot;});&quot;
       
       rest = prev + allNext.slice( next.length + 1 );
-      
     }
 
     rest = methods + rest;
@@ -203,25 +182,20 @@ function parse( aCode, p )
   // Do some tidying up, where necessary
   aCode = aCode.replace(/Processing.\w+ = function addMethod/g, &quot;addMethod&quot;);
   
-  function nextBrace( right )
-  {
+  function nextBrace( right ) {
     var rest = right;
     var position = 0;
     var leftCount = 1, rightCount = 0;
     
-    while ( leftCount != rightCount )
-    {
+    while ( leftCount != rightCount ) {
       var nextLeft = rest.indexOf(&quot;{&quot;);
       var nextRight = rest.indexOf(&quot;}&quot;);
       
-      if ( nextLeft &lt; nextRight &amp;&amp; nextLeft != -1 )
-      {
+      if ( nextLeft &lt; nextRight &amp;&amp; nextLeft != -1 ) {
         leftCount++;
         rest = rest.slice( nextLeft + 1 );
         position += nextLeft + 1;
-      }
-      else
-      {
+      } else {
         rightCount++;
         rest = rest.slice( nextRight + 1 );
         position += nextRight + 1;
@@ -263,7 +237,7 @@ function parse( aCode, p )
 //log(aCode);
 
   return aCode;
-}
+};
 
 function buildProcessing( curElement ){
 
@@ -275,19 +249,27 @@ function buildProcessing( curElement ){
   p.HALF_PI = p.PI / 2;
   p.P3D = 3;
   p.CORNER = 0;
-  p.CENTER = 1;
-  p.CENTER_RADIUS = 2;
-  p.RADIUS = 2;
-  p.POLYGON = 1;
+  p.RADIUS = 1;
+  p.CENTER_RADIUS = 1;
+  p.CENTER = 2;
+  p.POLYGON = 2;
+  p.QUADS = 5;
   p.TRIANGLES = 6;
   p.POINTS = 7;
   p.LINES = 8;
   p.TRIANGLE_STRIP = 9;
+  p.TRIANGLE_FAN = 4;
+  p.QUAD_STRIP = 3;
   p.CORNERS = 10;
   p.CLOSE = true;
   p.RGB = 1;
   p.HSB = 2;
 
+  // mouseButton constants: values adjusted to come directly from e.which
+  p.LEFT = 1;
+  p.CENTER = 2;
+  p.RIGHT = 3;
+
   // &quot;Private&quot; variables used to maintain state
   var curContext = curElement.getContext(&quot;2d&quot;);
   var doFill = true;
@@ -295,6 +277,7 @@ function buildProcessing( curElement ){
   var loopStarted = false;
   var hasBackground = false;
   var doLoop = true;
+  var looping = 0;
   var curRectMode = p.CORNER;
   var curEllipseMode = p.CENTER;
   var inSetup = false;
@@ -303,6 +286,8 @@ function buildProcessing( curElement ){
   var curFrameRate = 1000;
   var curShape = p.POLYGON;
   var curShapeCount = 0;
+  var curvePoints = [];
+  var curTightness = 0;
   var opacityRange = 255;
   var redRange = 255;
   var greenRange = 255;
@@ -310,7 +295,7 @@ function buildProcessing( curElement ){
   var pathOpen = false;
   var mousePressed = false;
   var keyPressed = false;
-  var firstX, firstY, prevX, prevY;
+  var firstX, firstY, secondX, secondY, prevX, prevY;
   var curColorMode = p.RGB;
   var curTint = -1;
   var curTextSize = 12;
@@ -323,6 +308,7 @@ function buildProcessing( curElement ){
   p.pmouseY = 0;
   p.mouseX = 0;
   p.mouseY = 0;
+  p.mouseButton = 0;
 
   // Will be replaced by the user, most likely
   p.mouseDragged = undefined;
@@ -337,63 +323,49 @@ function buildProcessing( curElement ){
   // The height/width of the canvas
   p.width = curElement.width - 0;
   p.height = curElement.height - 0;
+
+  // The current animation frame
+  p.frameCount = 0;
   
   // In case I ever need to do HSV conversion:
   // http://srufaculty.sru.edu/david.dailey/javascript/js/5rml.js
-  p.color = function color( aValue1, aValue2, aValue3, aValue4 )
-  {
+  p.color = function color( aValue1, aValue2, aValue3, aValue4 ) {
     var aColor = &quot;&quot;;
     
-    if ( arguments.length == 3 )
-    {
+    if ( arguments.length == 3 ) {
       aColor = p.color( aValue1, aValue2, aValue3, opacityRange );
-    }
-    else if ( arguments.length == 4 )
-    {
+    } else if ( arguments.length == 4 ) {
       var a = aValue4 / opacityRange;
       a = isNaN(a) ? 1 : a;
 
-      if ( curColorMode == p.HSB )
-      {
+      if ( curColorMode == p.HSB ) {
         var rgb = HSBtoRGB(aValue1, aValue2, aValue3);
         var r = rgb[0], g = rgb[1], b = rgb[2];
-      }
-      else
-      {
+      } else {
         var r = getColor(aValue1, redRange);
         var g = getColor(aValue2, greenRange);
         var b = getColor(aValue3, blueRange);
       }
 
       aColor = &quot;rgba(&quot; + r + &quot;,&quot; + g + &quot;,&quot; + b + &quot;,&quot; + a + &quot;)&quot;;
-    }
-    else if ( typeof aValue1 == &quot;string&quot; )
-    {
+    } else if ( typeof aValue1 == &quot;string&quot; ) {
       aColor = aValue1;
 
-      if ( arguments.length == 2 )
-      {
+      if ( arguments.length == 2 ) {
         var c = aColor.split(&quot;,&quot;);
-	c[3] = (aValue2 / opacityRange) + &quot;)&quot;;
-	aColor = c.join(&quot;,&quot;);
+        c[3] = (aValue2 / opacityRange) + &quot;)&quot;;
+        aColor = c.join(&quot;,&quot;);
       }
-    }
-    else if ( arguments.length == 2 )
-    {
+    } else if ( arguments.length == 2 ) {
       aColor = p.color( aValue1, aValue1, aValue1, aValue2 );
-    }
-    else if ( typeof aValue1 == &quot;number&quot; )
-    {
+    } else if ( typeof aValue1 == &quot;number&quot; ) {
       aColor = p.color( aValue1, aValue1, aValue1, opacityRange );
-    }
-    else
-    {
+    } else {
       aColor = p.color( redRange, greenRange, blueRange, opacityRange );
     }
 
     // HSB conversion function from Mootools, MIT Licensed
-    function HSBtoRGB(h, s, b)
-    {
+    function HSBtoRGB(h, s, b) {
       h = (h / redRange) * 100;
       s = (s / greenRange) * 100;
       b = (b / blueRange) * 100;
@@ -417,80 +389,66 @@ function buildProcessing( curElement ){
       }
     }
 
-    function getColor( aValue, range )
-    {
+    function getColor( aValue, range ) {
       return Math.round(255 * (aValue / range));
     }
     
     return aColor;
   }
 
-  p.nf = function( num, pad )
-  {
+  p.nf = function( num, pad ) {
     var str = &quot;&quot; + num;
     while ( pad - str.length )
       str = &quot;0&quot; + str;
     return str;
   };
 
-  p.AniSprite = function( prefix, frames )
-  {
+  p.AniSprite = function( prefix, frames ) {
     this.images = [];
     this.pos = 0;
 
-    for ( var i = 0; i &lt; frames; i++ )
-    {
+    for ( var i = 0; i &lt; frames; i++ ) {
       this.images.push( prefix + p.nf( i, (&quot;&quot; + frames).length ) + &quot;.gif&quot; );
     }
 
-    this.display = function( x, y )
-    {
+    this.display = function( x, y ) {
       p.image( this.images[ this.pos ], x, y );
 
       if ( ++this.pos &gt;= frames )
         this.pos = 0;
     };
 
-    this.getWidth = function()
-    {
+    this.getWidth = function() {
       return getImage(this.images[0]).width;
     };
 
-    this.getHeight = function()
-    {
+    this.getHeight = function() {
       return getImage(this.images[0]).height;
     };
   };
 
-  function buildImageObject( obj )
-  {
+  function buildImageObject( obj ) {
     var pixels = obj.data;
     var data = p.createImage( obj.width, obj.height );
 
-    if ( data.__defineGetter__ &amp;&amp; data.__lookupGetter__ &amp;&amp; !data.__lookupGetter__(&quot;pixels&quot;) )
-    {
+    if ( data.__defineGetter__ &amp;&amp; data.__lookupGetter__ &amp;&amp; !data.__lookupGetter__(&quot;pixels&quot;) ) {
       var pixelsDone;
-      data.__defineGetter__(&quot;pixels&quot;, function()
-      {
+      data.__defineGetter__(&quot;pixels&quot;, function() {
         if ( pixelsDone )
-	  return pixelsDone;
+          return pixelsDone;
 
-	pixelsDone = [];
+        pixelsDone = [];
 
-        for ( var i = 0; i &lt; pixels.length; i += 4 )
-        {
+        for ( var i = 0; i &lt; pixels.length; i += 4 ) {
           pixelsDone.push( p.color(pixels[i], pixels[i+1], pixels[i+2], pixels[i+3]) );
         }
 
-	return pixelsDone;
+        return pixelsDone;
       });
-    }
-    else
-    {
+    } else {
       data.pixels = [];
 
-      for ( var i = 0; i &lt; pixels.length; i += 4 )
-      {
+      for ( var i = 0; i &lt; pixels.length; i += 4 ) {
         data.pixels.push( p.color(pixels[i], pixels[i+1], pixels[i+2], pixels[i+3]) );
       }
     }
@@ -498,73 +456,62 @@ function buildProcessing( curElement ){
     return data;
   }
 
-  p.createImage = function createImage( w, h, mode )
-  {
-    var data = {
-      width: w,
-      height: h,
-      pixels: new Array( w * h ),
-      get: function(x,y)
-      {
-        return this.pixels[w*y+x];
-      },
-      _mask: null,
-      mask: function(img)
-      {
-        this._mask = img;
-      },
-      loadPixels: function()
-      {
-      },
-      updatePixels: function()
-      {
-      }
+  p.createImage = function createImage( w, h, mode ) {
+    var data = {};
+    data.width = w;
+    data.height = h;
+    data.data = [];
+
+    if ( curContext.createImageData ) {
+      data = curContext.createImageData( w, h );
+    }
+
+    data.pixels = new Array( w * h );
+    data.get = function(x,y) {
+      return this.pixels[w*y+x];
     };
+    data._mask = null;
+    data.mask = function(img) {
+      this._mask = img;
+    };
+    data.loadPixels = function(){};
+    data.updatePixels = function(){};
 
     return data;
-  }
+  };
 
-  p.createGraphics = function createGraphics( w, h )
-  {
+  p.createGraphics = function createGraphics( w, h ) {
     var canvas = document.createElement(&quot;canvas&quot;);
     var ret = buildProcessing( canvas );
     ret.size( w, h );
     ret.canvas = canvas;
     return ret;
-  }
-
-  p.beginDraw = function beginDraw()
-  {
-
-  }
+  };
 
-  p.endDraw = function endDraw()
-  {
+  p.beginDraw = function beginDraw(){};
 
-  }
+  p.endDraw = function endDraw(){};
 
-  p.tint = function tint( rgb, a )
-  {
+  p.tint = function tint( rgb, a ) {
     curTint = a;
-  }
+  };
 
   function getImage( img ) {
-    if ( typeof img == &quot;string&quot; )
-    {
+    if ( typeof img == &quot;string&quot; ) {
       return document.getElementById(img);
     }
 
-    if ( img.img || img.canvas )
-    {
+    if ( img.img || img.canvas ) {
       return img.img || img.canvas;
     }
 
-    img.data = [];
-
-    for ( var i = 0, l = img.pixels.length; i &lt; l; i++ )
-    {
+    for ( var i = 0, l = img.pixels.length; i &lt; l; i++ ) {
+      var pos = i * 4;
       var c = (img.pixels[i] || &quot;rgba(0,0,0,1)&quot;).slice(5,-1).split(&quot;,&quot;);
-      img.data.push( parseInt(c[0]), parseInt(c[1]), parseInt(c[2]), parseFloat(c[3]) * 100 );
+      img.data[pos] = parseInt(c[0]);
+      img.data[pos+1] = parseInt(c[1]);
+      img.data[pos+2] = parseInt(c[2]);
+      img.data[pos+3] = parseFloat(c[3]) * 100;
     }
 
     var canvas = document.createElement(&quot;canvas&quot;)
@@ -578,54 +525,42 @@ function buildProcessing( curElement ){
     return canvas;
   }
 
-  p.image = function image( img, x, y, w, h )
-  {
+  p.image = function image( img, x, y, w, h ) {
     x = x || 0;
     y = y || 0;
 
     var obj = getImage(img);
 
-    if ( curTint &gt;= 0 )
-    {
+    if ( curTint &gt;= 0 ) {
       var oldAlpha = curContext.globalAlpha;
       curContext.globalAlpha = curTint / opacityRange;
     }
 
-    if ( arguments.length == 3 )
-    {
+    if ( arguments.length == 3 ) {
       curContext.drawImage( obj, x, y );
-    }
-    else
-    {
+    } else {
       curContext.drawImage( obj, x, y, w, h );
     }
 
-    if ( curTint &gt;= 0 )
-    {
+    if ( curTint &gt;= 0 ) {
       curContext.globalAlpha = oldAlpha;
     }
 
-    if ( img._mask )
-    {
+    if ( img._mask ) {
       var oldComposite = curContext.globalCompositeOperation;
       curContext.globalCompositeOperation = &quot;darker&quot;;
       p.image( img._mask, x, y );
       curContext.globalCompositeOperation = oldComposite;
     }
-  }
-
-  p.exit = function exit()
-  {
+  };
 
-  }
+  p.exit = function exit() {
+    clearInterval(looping);
+  };
 
-  p.save = function save( file )
-  {
+  p.save = function save( file ){};
 
-  }
-
-  p.loadImage = function loadImage( file )
-  {
+  p.loadImage = function loadImage( file ) {
     var img = document.getElementById(file);
     if ( !img )
       return;
@@ -641,95 +576,74 @@ function buildProcessing( curElement ){
     var data = buildImageObject( context.getImageData( 0, 0, w, h ) );
     data.img = img;
     return data;
-  }
+  };
 
-  p.loadFont = function loadFont( name )
-  {
+  p.loadFont = function loadFont( name ) {
     return {
       name: name,
-      width: function( str )
-      {
+      width: function( str ) {
         if ( curContext.mozMeasureText )
           return curContext.mozMeasureText( typeof str == &quot;number&quot; ?
             String.fromCharCode( str ) :
             str) / curTextSize;
-	else
-	  return 0;
+        else
+          return 0;
       }
     };
-  }
+  };
 
-  p.textFont = function textFont( name, size )
-  {
+  p.textFont = function textFont( name, size ) {
     curTextFont = name;
     p.textSize( size );
-  }
+  };
 
-  p.textSize = function textSize( size )
-  {
-    if ( size )
-    {
+  p.textSize = function textSize( size ) {
+    if ( size ) {
       curTextSize = size;
     }
-  }
-
-  p.textAlign = function textAlign()
-  {
+  };
 
-  }
+  p.textAlign = function textAlign(){};
 
-  p.text = function text( str, x, y )
-  {
-    if ( str &amp;&amp; curContext.mozDrawText )
-    {
+  p.text = function text( str, x, y ) {
+    if ( str &amp;&amp; curContext.mozDrawText ) {
       curContext.save();
       curContext.mozTextStyle = curTextSize + &quot;px &quot; + curTextFont.name;
       curContext.translate(x, y);
       curContext.mozDrawText( typeof str == &quot;number&quot; ?
         String.fromCharCode( str ) :
-	str );
+        str );
       curContext.restore();
     }
-  }
+  };
 
-  p.char = function char( key )
-  {
-    //return String.fromCharCode( key );
+  p.char = function char( key ) {
     return key;
-  }
-
-  p.println = function println()
-  {
+  };
 
-  }
+  p.println = function println(){};
 
-  p.map = function map( value, istart, istop, ostart, ostop )
-  {
+  p.map = function map( value, istart, istop, ostart, ostop ) {
     return ostart + (ostop - ostart) * ((value - istart) / (istop - istart));
   };
 
-  String.prototype.replaceAll = function(re, replace)
-  {
+  String.prototype.replaceAll = function(re, replace) {
     return this.replace(new RegExp(re, &quot;g&quot;), replace);
   };
 
-  p.Point = function Point( x, y )
-  {
+  p.Point = function Point( x, y ) {
     this.x = x;
     this.y = y;
-    this.copy = function()
-    {
+    this.copy = function() {
       return new Point( x, y );
     }
-  }
+  };
 
-  p.Random = function()
-  {
+  p.Random = function() {
     var haveNextNextGaussian = false;
     var nextNextGaussian;
 
-    this.nextGaussian = function()
-    {
+    this.nextGaussian = function() {
       if (haveNextNextGaussian) {
         haveNextNextGaussian = false;
 
@@ -748,106 +662,84 @@ function buildProcessing( curElement ){
         return v1 * multiplier;
       }
     };
-  }
+  };
 
-  p.ArrayList = function ArrayList( size, size2, size3 )
-  {
+  p.ArrayList = function ArrayList( size, size2, size3 ) {
     var array = new Array( 0 | size );
     
-    if ( size2 )
-    {
-      for ( var i = 0; i &lt; size; i++ )
-      {
+    if ( size2 ) {
+      for ( var i = 0; i &lt; size; i++ ) {
         array[i] = [];
 
-        for ( var j = 0; j &lt; size2; j++ )
-        {
-	  var a = array[i][j] = size3 ? new Array( size3 ) : 0;
-	  for ( var k = 0; k &lt; size3; k++ )
-	  {
-	    a[k] = 0;
-	  }
+        for ( var j = 0; j &lt; size2; j++ ) {
+          var a = array[i][j] = size3 ? new Array( size3 ) : 0;
+          for ( var k = 0; k &lt; size3; k++ ) {
+            a[k] = 0;
+          }
         }
       }
-    }
-    else
-    {
-      for ( var i = 0; i &lt; size; i++ )
-      {
+    } else {
+      for ( var i = 0; i &lt; size; i++ ) {
         array[i] = 0;
       }
     }
     
-    array.size = function()
-    {
+    array.size = function() {
       return this.length;
     };
-    array.get = function( i )
-    {
+    array.get = function( i ) {
       return this[ i ];
     };
-    array.remove = function( i )
-    {
+    array.remove = function( i ) {
       return this.splice( i, 1 );
     };
-    array.add = function( item )
-    {
-      for ( var i = 0; this[ i ] != undefined; i++ ) {}
-      this[ i ] = item;
+    array.add = function( item ) {
+      return this.push( item );
     };
-    array.clone = function()
-    {
+    array.clone = function() {
       var a = new ArrayList( size );
-      for ( var i = 0; i &lt; size; i++ )
-      {
+      for ( var i = 0; i &lt; size; i++ ) {
         a[ i ] = this[ i ];
       }
       return a;
     };
-    array.isEmpty = function()
-    {
+    array.isEmpty = function() {
       return !this.length;
     };
-    array.clear = function()
-    {
+    array.clear = function() {
       this.length = 0;
     };
     
     return array;
-  }
+  };
   
-  p.colorMode = function colorMode( mode, range1, range2, range3, range4 )
-  {
+  p.colorMode = function colorMode( mode, range1, range2, range3, range4 ) {
     curColorMode = mode;
 
-    if ( arguments.length &gt;= 4 )
-    {
+    if ( arguments.length &gt;= 4 ) {
       redRange = range1;
       greenRange = range2;
       blueRange = range3;
     }
 
-    if ( arguments.length == 5 )
-    {
+    if ( arguments.length == 5 ) {
       opacityRange = range4;
     }
 
-    if ( arguments.length == 2 )
-    {
+    if ( arguments.length == 2 ) {
       p.colorMode( mode, range1, range1, range1, range1 );
     }
-  }
+  };
   
-  p.beginShape = function beginShape( type )
-  {
+  p.beginShape = function beginShape( type ) {
     curShape = type;
     curShapeCount = 0; 
-  }
+    curvePoints = [];
+  };
   
-  p.endShape = function endShape( close )
-  {
-    if ( curShapeCount != 0 )
-    {
+  p.endShape = function endShape( close ) {
+    if ( curShapeCount != 0 ) {
+      if ( close || doFill ) 
       curContext.lineTo( firstX, firstY );
 
       if ( doFill )
@@ -861,317 +753,326 @@ function buildProcessing( curElement ){
       pathOpen = false;
     }
 
-    if ( pathOpen )
-    {
+    if ( pathOpen ) {
+      if ( doFill )
+        curContext.fill();
+
+      if ( doStroke )
+        curContext.stroke();
+
       curContext.closePath();
+      curShapeCount = 0;
+      pathOpen = false;
     }
-  }
+  };
   
-  p.vertex = function vertex( x, y, x2, y2, x3, y3 )
-  {
-    if ( curShapeCount == 0 &amp;&amp; curShape != p.POINTS )
-    {
+  p.vertex = function vertex( x, y, x2, y2, x3, y3 ) {
+    if ( curShapeCount == 0 &amp;&amp; curShape != p.POINTS ) {
       pathOpen = true;
       curContext.beginPath();
       curContext.moveTo( x, y );
-    }
-    else
-    {
-      if ( curShape == p.POINTS )
-      {
+      firstX = x;
+      firstY = y;
+    } else {
+      if ( curShape == p.POINTS ) {
         p.point( x, y );
-      }
-      else if ( arguments.length == 2 )
-      {
-        if ( curShape == p.TRIANGLE_STRIP &amp;&amp; curShapeCount == 2 )
-	{
+      } else if ( arguments.length == 2 ) {
+        if ( curShape != p.QUAD_STRIP || curShapeCount != 2 )
+          curContext.lineTo( x, y );
+
+        if ( curShape == p.TRIANGLE_STRIP ) {
+          if ( curShapeCount == 2 ) {
+            // finish shape
+            p.endShape(p.CLOSE);
+            pathOpen = true;
+            curContext.beginPath();
+            
+            // redraw last line to start next shape
+            curContext.moveTo( prevX, prevY );
+            curContext.lineTo( x, y );
+            curShapeCount = 1;
+          }
+          firstX = prevX;
+          firstY = prevY;
+        }
+
+        if ( curShape == p.TRIANGLE_FAN &amp;&amp; curShapeCount == 2 ) {
+          // finish shape
+          p.endShape(p.CLOSE);
+          pathOpen = true;
+          curContext.beginPath();
+      
+          // redraw last line to start next shape
+          curContext.moveTo( firstX, firstY );
+          curContext.lineTo( x, y );
+          curShapeCount = 1;
+        }
+    
+        if ( curShape == p.QUAD_STRIP &amp;&amp; curShapeCount == 3 ) {
+          // finish shape
+          curContext.lineTo( prevX, prevY );
+          p.endShape(p.CLOSE);
+          pathOpen = true;
+          curContext.beginPath();
+    
+          // redraw lines to start next shape
           curContext.moveTo( prevX, prevY );
-          curContext.lineTo( firstX, firstY );
-	}
+          curContext.lineTo( x, y );
+          curShapeCount = 1;
+        }
 
-        curContext.lineTo( x, y );
-      }
-      else if ( arguments.length == 4 )
-      {
-        if ( curShapeCount &gt; 1 )
-        {
-	  curContext.moveTo( prevX, prevY );
+        if ( curShape == p.QUAD_STRIP) {
+          firstX = secondX;
+          firstY = secondY;
+          secondX = prevX;
+          secondY = prevY;
+        }
+      } else if ( arguments.length == 4 ) {
+        if ( curShapeCount &gt; 1 ) {
+          curContext.moveTo( prevX, prevY );
           curContext.quadraticCurveTo( firstX, firstY, x, y );
-	  curShapeCount = 1;
+          curShapeCount = 1;
         }
-      }
-      else if ( arguments.length == 6 )
-      {
+      } else if ( arguments.length == 6 ) {
         curContext.bezierCurveTo( x, y, x2, y2, x3, y3 );
         curShapeCount = -1;
       }
     }
 
-    prevX = firstX;
-    prevY = firstY;
-    firstX = x;
-    firstY = y;
-
-    
+    prevX = x;
+    prevY = y;
     curShapeCount++;
     
     if ( curShape == p.LINES &amp;&amp; curShapeCount == 2 ||
-         (curShape == p.TRIANGLES || curShape == p.TRIANGLE_STRIP) &amp;&amp; curShapeCount == 3 )
-    {
-      p.endShape();
-    }
-
-    if ( curShape == p.TRIANGLE_STRIP &amp;&amp; curShapeCount == 3 )
-    {
-      curShapeCount = 2;
+         (curShape == p.TRIANGLES) &amp;&amp; curShapeCount == 3 ||
+     (curShape == p.QUADS) &amp;&amp; curShapeCount == 4 ) {
+      p.endShape(p.CLOSE);
     }
-  }
+  };
 
-  p.curveTightness = function()
-  {
+  p.curveVertex = function( x, y, x2, y2 ) {
+    if ( curvePoints.length &lt; 3 ) {
+      curvePoints.push([x,y]);
+    } else {
+      var b = [], s = 1 - curTightness;
+
+      /*
+       * Matrix to convert from Catmull-Rom to cubic Bezier
+       * where t = curTightness
+       * |0         1          0         0       |
+       * |(t-1)/6   1          (1-t)/6   0       |
+       * |0         (1-t)/6    1         (t-1)/6 |
+       * |0         0          0         0       |
+       */
+
+      curvePoints.push([x,y]);
+
+      b[0] = [curvePoints[1][0],curvePoints[1][1]];
+      b[1] = [curvePoints[1][0]+(s*curvePoints[2][0]-s*curvePoints[0][0])/6,curvePoints[1][1]+(s*curvePoints[2][1]-s*curvePoints[0][1])/6];
+      b[2] = [curvePoints[2][0]+(s*curvePoints[1][0]-s*curvePoints[3][0])/6,curvePoints[2][1]+(s*curvePoints[1][1]-s*curvePoints[3][1])/6];
+      b[3] = [curvePoints[2][0],curvePoints[2][1]];
+
+      if ( !pathOpen ) {
+        p.vertex( b[0][0], b[0][1] );
+      } else {
+        curShapeCount = 1;
+      }
 
-  }
+      p.vertex( b[1][0], b[1][1], b[2][0], b[2][1], b[3][0], b[3][1] );
+      curvePoints.shift();
+    }
+  };
 
-  // Unimplmented - not really possible with the Canvas API
-  p.curveVertex = function( x, y, x2, y2 )
-  {
-    p.vertex( x, y, x2, y2 );
-  }
+  p.curveTightness = function( tightness ) {
+    curTightness = tightness;
+  };
 
-  p.bezierVertex = p.vertex
+  p.bezierVertex = p.vertex;
   
-  p.rectMode = function rectMode( aRectMode )
-  {
+  p.rectMode = function rectMode( aRectMode ) {
     curRectMode = aRectMode;
-  }
-
-  p.imageMode = function()
-  {
+  };
 
-  }
+  p.imageMode = function(){};
   
-  p.ellipseMode = function ellipseMode( aEllipseMode )
-  {
+  p.ellipseMode = function ellipseMode( aEllipseMode ) {
     curEllipseMode = aEllipseMode;
-  }
+  };
   
-  p.dist = function dist( x1, y1, x2, y2 )
-  {
+  p.dist = function dist( x1, y1, x2, y2 ) {
     return Math.sqrt( Math.pow( x2 - x1, 2 ) + Math.pow( y2 - y1, 2 ) );
-  }
+  };
 
-  p.year = function year()
-  {
+  p.year = function year() {
     return (new Date).getYear() + 1900;
-  }
+  };
 
-  p.month = function month()
-  {
+  p.month = function month() {
     return (new Date).getMonth();
-  }
+  };
 
-  p.day = function day()
-  {
+  p.day = function day() {
     return (new Date).getDay();
-  }
+  };
 
-  p.hour = function hour()
-  {
+  p.hour = function hour() {
     return (new Date).getHours();
-  }
+  };
 
-  p.minute = function minute()
-  {
+  p.minute = function minute() {
     return (new Date).getMinutes();
-  }
+  };
 
-  p.second = function second()
-  {
+  p.second = function second() {
     return (new Date).getSeconds();
-  }
+  };
 
-  p.millis = function millis()
-  {
+  p.millis = function millis() {
     return (new Date).getTime() - start;
-  }
+  };
   
-  p.ortho = function ortho()
-  {
+  p.ortho = function ortho(){};
   
-  }
-  
-  p.translate = function translate( x, y )
-  {
+  p.translate = function translate( x, y ) {
     curContext.translate( x, y );
-  }
+  };
   
-  p.scale = function scale( x, y )
-  {
+  p.scale = function scale( x, y ) {
     curContext.scale( x, y || x );
-  }
+  };
   
-  p.rotate = function rotate( aAngle )
-  {
+  p.rotate = function rotate( aAngle ) {
     curContext.rotate( aAngle );
-  }
+  };
   
-  p.pushMatrix = function pushMatrix()
-  {
+  p.pushMatrix = function pushMatrix() {
     curContext.save();
-  }
+  };
   
-  p.popMatrix = function popMatrix()
-  {
+  p.popMatrix = function popMatrix() {
     curContext.restore();
-  }
+  };
   
-  p.redraw = function redraw()
-  {
-    if ( hasBackground )
-    {
+  p.redraw = function redraw() {
+    if ( hasBackground ) {
       p.background();
     }
+
+    p.frameCount++;
     
     inDraw = true;
     p.pushMatrix();
     p.draw();
     p.popMatrix();
     inDraw = false;
-  }
+  };
   
-  p.loop = function loop()
-  {
+  p.loop = function loop() {
     if ( loopStarted )
       return;
     
-    var looping = setInterval(function()
-    {
-      try
-      {
+    looping = setInterval(function() {
+      try {
         p.redraw();
       }
-      catch(e)
-      {
+      catch(e) {
         clearInterval( looping );
         throw e;
       }
     }, 1000 / curFrameRate );
     
     loopStarted = true;
-  }
+  };
   
-  p.frameRate = function frameRate( aRate )
-  {
+  p.frameRate = function frameRate( aRate ) {
     curFrameRate = aRate;
-  }
+  };
   
-  p.background = function background( img )
-  {
-    if ( arguments.length )
-    {
-      if ( img &amp;&amp; img.img )
-      {
+  p.background = function background( img ) {
+    if ( arguments.length ) {
+      if ( img &amp;&amp; img.img ) {
         curBackground = img;
-      }
-      else
-      {
+      } else {
         curBackground = p.color.apply( this, arguments );
       }
     }
     
 
-    if ( curBackground.img )
-    {
+    if ( curBackground.img ) {
       p.image( curBackground, 0, 0 );
-    }
-    else
-    {
+    } else {
       var oldFill = curContext.fillStyle;
       curContext.fillStyle = curBackground + &quot;&quot;;
       curContext.fillRect( 0, 0, p.width, p.height );
       curContext.fillStyle = oldFill;
     }
-  }
+  };
 
-  p.sq = function sq( aNumber )
-  {
+  p.sq = function sq( aNumber ) {
     return aNumber * aNumber;
-  }
+  };
 
-  p.sqrt = function sqrt( aNumber )
-  {
+  p.sqrt = function sqrt( aNumber ) {
     return Math.sqrt( aNumber );
-  }
+  };
   
-  p.int = function int( aNumber )
-  {
+  p.int = function int( aNumber ) {
     return Math.floor( aNumber );
-  }
+  };
 
-  p.min = function min( aNumber, aNumber2 )
-  {
+  p.min = function min( aNumber, aNumber2 ) {
     return Math.min( aNumber, aNumber2 );
-  }
+  };
 
-  p.max = function max( aNumber, aNumber2 )
-  {
+  p.max = function max( aNumber, aNumber2 ) {
     return Math.max( aNumber, aNumber2 );
-  }
+  };
 
-  p.ceil = function ceil( aNumber )
-  {
+  p.ceil = function ceil( aNumber ) {
     return Math.ceil( aNumber );
-  }
+  };
 
-  p.floor = function floor( aNumber )
-  {
+  p.floor = function floor( aNumber ) {
     return Math.floor( aNumber );
-  }
+  };
 
-  p.float = function float( aNumber )
-  {
+  p.float = function float( aNumber ) {
     return typeof aNumber == &quot;string&quot; ?
-	p.float( aNumber.charCodeAt(0) ) :
-        parseFloat( aNumber );
-  }
+      p.float( aNumber.charCodeAt(0) ) :
+      parseFloat( aNumber );
+  };
 
-  p.byte = function byte( aNumber )
-  {
+  p.byte = function byte( aNumber ) {
     return aNumber || 0;
-  }
+  };
   
-  p.random = function random( aMin, aMax )
-  {
+  p.random = function random( aMin, aMax ) {
     return arguments.length == 2 ?
       aMin + (Math.random() * (aMax - aMin)) :
       Math.random() * aMin;
-  }
+  };
 
   // From: http://freespace.virgin.net/hugo.elias/models/m_perlin.htm
-  p.noise = function( x, y, z )
-  {
+  p.noise = function( x, y, z ) {
     return arguments.length &gt;= 2 ?
       PerlinNoise_2D( x, y ) :
       PerlinNoise_2D( x, x );
-  }
+  };
 
-  function Noise(x, y)
-  {
+  function Noise(x, y) {
     var n = x + y * 57;
     n = (n&lt;&lt;13) ^ n;
     return Math.abs(1.0 - (((n * ((n * n * 15731) + 789221) + 1376312589) &amp; 0x7fffffff) / 1073741824.0));
-  }
+  };
 
-  function SmoothedNoise(x, y)
-  {
+  function SmoothedNoise(x, y) {
     var corners = ( Noise(x-1, y-1)+Noise(x+1, y-1)+Noise(x-1, y+1)+Noise(x+1, y+1) ) / 16;
     var sides   = ( Noise(x-1, y)  +Noise(x+1, y)  +Noise(x, y-1)  +Noise(x, y+1) ) /  8;
     var center  =  Noise(x, y) / 4;
     return corners + sides + center;
-  }
+  };
 
-  function InterpolatedNoise(x, y)
-  {
+  function InterpolatedNoise(x, y) {
     var integer_X    = Math.floor(x);
     var fractional_X = x - integer_X;
 
@@ -1189,14 +1090,12 @@ function buildProcessing( curElement ){
     return Interpolate(i1 , i2 , fractional_Y);
   }
 
-  function PerlinNoise_2D(x, y)
-  {
+  function PerlinNoise_2D(x, y) {
       var total = 0;
       var p = 0.25;
       var n = 3;
 
-      for ( var i = 0; i &lt;= n; i++ )
-      {
+      for ( var i = 0; i &lt;= n; i++ ) {
           var frequency = Math.pow(2, i);
           var amplitude = Math.pow(p, i);
 
@@ -1206,75 +1105,61 @@ function buildProcessing( curElement ){
       return total;
   }
 
-  function Interpolate(a, b, x)
-  {
+  function Interpolate(a, b, x) {
     var ft = x * p.PI;
     var f = (1 - p.cos(ft)) * .5;
     return  a*(1-f) + b*f;
   }
 
-  p.red = function( aColor )
-  {
+  p.red = function( aColor ) {
     return parseInt(aColor.slice(5));
-  }
+  };
 
-  p.green = function( aColor )
-  {
+  p.green = function( aColor ) {
     return parseInt(aColor.split(&quot;,&quot;)[1]);
-  }
+  };
 
-  p.blue = function( aColor )
-  {
+  p.blue = function( aColor ) {
     return parseInt(aColor.split(&quot;,&quot;)[2]);
-  }
+  };
 
-  p.alpha = function( aColor )
-  {
+  p.alpha = function( aColor ) {
     return parseInt(aColor.split(&quot;,&quot;)[3]);
-  }
+  };
 
-  p.abs = function abs( aNumber )
-  {
+  p.abs = function abs( aNumber ) {
     return Math.abs( aNumber );
-  }
+  };
   
-  p.cos = function cos( aNumber )
-  {
+  p.cos = function cos( aNumber ) {
     return Math.cos( aNumber );
-  }
+  };
   
-  p.sin = function sin( aNumber )
-  {
+  p.sin = function sin( aNumber ) {
     return Math.sin( aNumber );
-  }
+  };
   
-  p.pow = function pow( aNumber, aExponent )
-  {
+  p.pow = function pow( aNumber, aExponent ) {
     return Math.pow( aNumber, aExponent );
-  }
+  };
   
-  p.constrain = function constrain( aNumber, aMin, aMax )
-  {
+  p.constrain = function constrain( aNumber, aMin, aMax ) {
     return Math.min( Math.max( aNumber, aMin ), aMax );
-  }
+  };
   
-  p.sqrt = function sqrt( aNumber )
-  {
-  	return Math.sqrt( aNumber );
-  }
+  p.sqrt = function sqrt( aNumber ) {
+    return Math.sqrt( aNumber );
+  };
   
-  p.atan2 = function atan2( aNumber, aNumber2 )
-  {
-  	return Math.atan2( aNumber, aNumber2 );
-  }
+  p.atan2 = function atan2( aNumber, aNumber2 ) {
+    return Math.atan2( aNumber, aNumber2 );
+  };
   
-  p.radians = function radians( aAngle )
-  {
+  p.radians = function radians( aAngle ) {
     return ( aAngle / 180 ) * p.PI;
-  }
+  };
   
-  p.size = function size( aWidth, aHeight )
-  {
+  p.size = function size( aWidth, aHeight ) {
     var fillStyle = curContext.fillStyle;
     var strokeStyle = curContext.strokeStyle;
 
@@ -1283,85 +1168,74 @@ function buildProcessing( curElement ){
 
     curContext.fillStyle = fillStyle;
     curContext.strokeStyle = strokeStyle;
-  }
+  };
   
-  p.noStroke = function noStroke()
-  {
+  p.noStroke = function noStroke() {
     doStroke = false;
-  }
+  };
   
-  p.noFill = function noFill()
-  {
+  p.noFill = function noFill() {
     doFill = false;
-  }
-  
-  p.smooth = function smooth()
-  {
+  };
   
-  }
+  p.smooth = function smooth(){};
   
-  p.noLoop = function noLoop()
-  {
+  p.noLoop = function noLoop() {
     doLoop = false;
-  }
+  };
   
-  p.fill = function fill()
-  {
+  p.fill = function fill() {
     doFill = true;
     curContext.fillStyle = p.color.apply( this, arguments );
-  }
+  };
   
-  p.stroke = function stroke()
-  {
+  p.stroke = function stroke() {
     doStroke = true;
     curContext.strokeStyle = p.color.apply( this, arguments );
-  }
+  };
 
-  p.strokeWeight = function strokeWeight( w )
-  {
+  p.strokeWeight = function strokeWeight( w ) {
     curContext.lineWidth = w;
-  }
+  };
   
-  p.point = function point( x, y )
-  {
+  p.point = function point( x, y ) {
     var oldFill = curContext.fillStyle;
     curContext.fillStyle = curContext.strokeStyle;
     curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 );
     curContext.fillStyle = oldFill;
-  }
+  };
 
-  p.get = function get( x, y )
-  {
-    if ( arguments.length == 0 )
-    {
+  p.get = function get( x, y ) {
+    if ( arguments.length == 0 ) {
       var c = p.createGraphics( p.width, p.height );
       c.image( curContext, 0, 0 );
       return c;
     }
 
-    if ( !getLoaded )
-    {
+    if ( !getLoaded ) {
       getLoaded = buildImageObject( curContext.getImageData(0, 0, p.width, p.height) );
     }
 
     return getLoaded.get( x, y );
-  }
+  };
 
-  p.set = function set( x, y, color )
-  {
-    var oldFill = curContext.fillStyle;
-    curContext.fillStyle = color;
-    curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 );
-    curContext.fillStyle = oldFill;
-  }
+  p.set = function set( x, y, obj ) {
+    if ( obj &amp;&amp; obj.img ) {
+      p.image( obj, x, y );
+    } else {
+      var oldFill = curContext.fillStyle;
+      var color = obj;
+      curContext.fillStyle = color;
+      curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 );
+      curContext.fillStyle = oldFill;
+    }
+  };
   
-  p.arc = function arc( x, y, width, height, start, stop )
-  {
+  p.arc = function arc( x, y, width, height, start, stop ) {
     if ( width &lt;= 0 )
       return;
 
-    if ( curEllipseMode == p.CORNER )
-    {
+    if ( curEllipseMode == p.CORNER ) {
       x += width / 2;
       y += height / 2;
     }
@@ -1378,10 +1252,9 @@ function buildProcessing( curElement ){
       curContext.stroke();
     
     curContext.closePath();
-  }
+  };
   
-  p.line = function line( x1, y1, x2, y2 )
-  {
+  p.line = function line( x1, y1, x2, y2 ) {
     curContext.lineCap = &quot;round&quot;;
     curContext.beginPath();
   
@@ -1391,10 +1264,9 @@ function buildProcessing( curElement ){
     curContext.stroke();
     
     curContext.closePath();
-  }
+  };
 
-  p.bezier = function bezier( x1, y1, x2, y2, x3, y3, x4, y4 )
-  {
+  p.bezier = function bezier( x1, y1, x2, y2, x3, y3, x4, y4 ) {
     curContext.lineCap = &quot;butt&quot;;
     curContext.beginPath();
   
@@ -1404,29 +1276,26 @@ function buildProcessing( curElement ){
     curContext.stroke();
     
     curContext.closePath();
-  }
+  };
 
-  p.triangle = function triangle( x1, y1, x2, y2, x3, y3 )
-  {
+  p.triangle = function triangle( x1, y1, x2, y2, x3, y3 ) {
     p.beginShape();
     p.vertex( x1, y1 );
     p.vertex( x2, y2 );
     p.vertex( x3, y3 );
     p.endShape();
-  }
+  };
 
-  p.quad = function quad( x1, y1, x2, y2, x3, y3, x4, y4 )
-  {
+  p.quad = function quad( x1, y1, x2, y2, x3, y3, x4, y4 ) {
     p.beginShape();
     p.vertex( x1, y1 );
     p.vertex( x2, y2 );
     p.vertex( x3, y3 );
     p.vertex( x4, y4 );
     p.endShape();
-  }
+  };
   
-  p.rect = function rect( x, y, width, height )
-  {
+  p.rect = function rect( x, y, width, height ) {
     if ( width == 0 &amp;&amp; height == 0 )
       return;
 
@@ -1435,20 +1304,17 @@ function buildProcessing( curElement ){
     var offsetStart = 0;
     var offsetEnd = 0;
 
-    if ( curRectMode == p.CORNERS )
-    {
+    if ( curRectMode == p.CORNERS ) {
       width -= x;
       height -= y;
     }
     
-    if ( curRectMode == p.RADIUS )
-    {
+    if ( curRectMode == p.RADIUS ) {
       width *= 2;
       height *= 2;
     }
     
-    if ( curRectMode == p.CENTER || curRectMode == p.RADIUS )
-    {
+    if ( curRectMode == p.CENTER || curRectMode == p.RADIUS ) {
       x -= width / 2;
       y -= height / 2;
     }
@@ -1467,10 +1333,9 @@ function buildProcessing( curElement ){
       curContext.stroke();
     
     curContext.closePath();
-  }
+  };
   
-  p.ellipse = function ellipse( x, y, width, height )
-  {
+  p.ellipse = function ellipse( x, y, width, height ) {
     x = x || 0;
     y = y || 0;
 
@@ -1479,8 +1344,7 @@ function buildProcessing( curElement ){
 
     curContext.beginPath();
     
-    if ( curEllipseMode == p.RADIUS )
-    {
+    if ( curEllipseMode == p.RADIUS ) {
       width *= 2;
       height *= 2;
     }
@@ -1498,26 +1362,28 @@ function buildProcessing( curElement ){
       curContext.stroke();
     
     curContext.closePath();
-  }
+  };
 
-  p.link = function( href, target )
-  {
+  p.link = function( href, target ) {
     window.location = href;
-  }
+  };
 
-  p.loadPixels = function()
-  {
+  p.loadPixels = function() {
     p.pixels = buildImageObject( curContext.getImageData(0, 0, p.width, p.height) ).pixels;
-  }
+  };
 
-  p.updatePixels = function()
-  {
+  p.updatePixels = function() {
     var colors = /(\d+),(\d+),(\d+),(\d+)/;
     var pixels = {};
-    var data = pixels.data = [];
     pixels.width = p.width;
     pixels.height = p.height;
+    pixels.data = [];
+
+    if ( curContext.createImageData ) {
+      pixels = curContext.createImageData( p.width, p.height );
+    }
 
+    var data = pixels.data;
     var pos = 0;
 
     for ( var i = 0, l = p.pixels.length; i &lt; l; i++ ) {
@@ -1530,40 +1396,31 @@ function buildProcessing( curElement ){
     }
 
     curContext.putImageData(pixels, 0, 0);
-  }
+  };
 
-  p.extendClass = function extendClass( obj, args, fn )
-  {
-    if ( arguments.length == 3 )
-    {
+  p.extendClass = function extendClass( obj, args, fn ) {
+    if ( arguments.length == 3 ) {
       fn.apply( obj, args );
-    }
-    else
-    {
+    } else {
       args.call( obj );
     }
-  }
+  };
 
-  p.addMethod = function addMethod( object, name, fn )
-  {
-    if ( object[ name ] )
-    {
+  p.addMethod = function addMethod( object, name, fn ) {
+    if ( object[ name ] ) {
       var args = fn.length;
       
       var oldfn = object[ name ];
-      object[ name ] = function()
-      {
+      object[ name ] = function() {
         if ( arguments.length == args )
           return fn.apply( this, arguments );
         else
           return oldfn.apply( this, arguments );
       };
-    }
-    else
-    {
+    } else {
       object[ name ] = fn;
     }
-  }
+  };
 
   p.init = function init(code){
     p.stroke( 0 );
@@ -1573,118 +1430,101 @@ function buildProcessing( curElement ){
     // counts, so we slightly offset it (this is super lame).
     curContext.translate( 0.5, 0.5 );
 
-    if ( code )
-    {
+    if ( code ) {
       (function(Processing){with (p){
         eval(parse(code, p));
       }})(p);
     }
   
-    if ( p.setup )
-    {
+    if ( p.setup ) {
       inSetup = true;
       p.setup();
     }
     
     inSetup = false;
     
-    if ( p.draw )
-    {
-      if ( !doLoop )
-      {
+    if ( p.draw ) {
+      if ( !doLoop ) {
         p.redraw();
-      }
-      else
-      {
+      } else {
         p.loop();
       }
     }
     
-    attach( curElement, &quot;mousemove&quot;, function(e)
-    {
+    attach( curElement, &quot;mousemove&quot;, function(e) {
+      var scrollX = window.scrollX != null ? window.scrollX : window.pageXOffset;
+      var scrollY = window.scrollY != null ? window.scrollY : window.pageYOffset;
       p.pmouseX = p.mouseX;
       p.pmouseY = p.mouseY;
-      p.mouseX = e.clientX - curElement.offsetLeft;
-      p.mouseY = e.clientY - curElement.offsetTop;
+      p.mouseX = e.clientX - curElement.offsetLeft + scrollX;
+      p.mouseY = e.clientY - curElement.offsetTop + scrollY;
 
-      if ( p.mouseMoved )
-      {
+      if ( p.mouseMoved ) {
         p.mouseMoved();
       }      
 
-      if ( mousePressed &amp;&amp; p.mouseDragged )
-      {
+      if ( mousePressed &amp;&amp; p.mouseDragged ) {
         p.mouseDragged();
       }      
     });
     
-    attach( curElement, &quot;mousedown&quot;, function(e)
-    {
+    attach( curElement, &quot;mousedown&quot;, function(e) {
       mousePressed = true;
+      p.mouseButton = e.which;
 
-      if ( typeof p.mousePressed == &quot;function&quot; )
-      {
+      if ( typeof p.mousePressed == &quot;function&quot; ) {
         p.mousePressed();
-      }
-      else
-      {
+      } else {
         p.mousePressed = true;
       }
     });
-      
-    attach( curElement, &quot;mouseup&quot;, function(e)
-    {
+
+    attach( curElement, &quot;contextmenu&quot;, function(e) {
+      e.preventDefault();
+      e.stopPropagation();
+    });
+
+    attach( curElement, &quot;mouseup&quot;, function(e) {
       mousePressed = false;
 
-      if ( typeof p.mousePressed != &quot;function&quot; )
-      {
+      if ( typeof p.mousePressed != &quot;function&quot; ) {
         p.mousePressed = false;
       }
 
-      if ( p.mouseReleased )
-      {
+      if ( p.mouseReleased ) {
         p.mouseReleased();
       }
     });
 
-    attach( document, &quot;keydown&quot;, function(e)
-    {
+    attach( document, &quot;keydown&quot;, function(e) {
       keyPressed = true;
 
       p.key = e.keyCode + 32;
 
-      if ( e.shiftKey )
-      {
+      if ( e.shiftKey ) {
         p.key = String.fromCharCode(p.key).toUpperCase().charCodeAt(0);
       }
 
-      if ( typeof p.keyPressed == &quot;function&quot; )
-      {
+      if ( typeof p.keyPressed == &quot;function&quot; ) {
         p.keyPressed();
-      }
-      else
-      {
+      } else {
         p.keyPressed = true;
       }
     });
 
-    attach( document, &quot;keyup&quot;, function(e)
-    {
+    attach( document, &quot;keyup&quot;, function(e) {
       keyPressed = false;
 
-      if ( typeof p.keyPressed != &quot;function&quot; )
-      {
+      if ( typeof p.keyPressed != &quot;function&quot; ) {
         p.keyPressed = false;
       }
 
-      if ( p.keyReleased )
-      {
+      if ( p.keyReleased ) {
         p.keyReleased();
       }
     });
 
-    function attach(elem, type, fn)
-    {
+    function attach(elem, type, fn) {
       if ( elem.addEventListener )
         elem.addEventListener( type, fn, false );
       else</diff>
      <filename>processing.js</filename>
    </modified>
    <modified>
      <diff>@@ -1,27 +1,31 @@
 &lt;!DOCTYPE HTML PUBLIC &quot;-//IETF//DTD HTML//EN&quot;&gt;
 &lt;html&gt; &lt;head&gt;
 &lt;title&gt;Processed Tower Defense&lt;/title&gt;
-&lt;script type=&quot;text/javascript&quot; src=&quot;processing.js&quot;&gt;&lt;/script&gt;
-&lt;script type=&quot;text/javascript&quot; src=&quot;jsfprocessing.js&quot;&gt;&lt;/script&gt;
-&lt;script type=&quot;text/javascript&quot; src=&quot;ptd.js&quot;&gt;&lt;/script&gt;
-
+&lt;script type=&quot;text/javascript&quot; charset=&quot;utf-8&quot; src=&quot;processing.js&quot;&gt;&lt;/script&gt;
+&lt;script type=&quot;text/javascript&quot; charset=&quot;utf-8&quot; src=&quot;jsfprocessing.js&quot;&gt;&lt;/script&gt;
+&lt;script type=&quot;text/javascript&quot; charset=&quot;utf-8&quot; src=&quot;ptd.js&quot;&gt;&lt;/script&gt;
+&lt;script type=&quot;text/javascript&quot; charset=&quot;utf-8&quot; src=&quot;jquery-1.2.6.min.js&quot;&gt;&lt;/script&gt;
+&lt;link href=&quot;style.css&quot; media=&quot;screen&quot; rel=&quot;Stylesheet&quot; type=&quot;text/css&quot; /&gt; 
 
 &lt;/head&gt;
 
 &lt;body onload=&quot;start_tower_defense();&quot;&gt;
 &lt;h1&gt; Processed Tower Defense &lt;/h1&gt;
 
+&lt;div id=&quot;game&quot;&gt;
+&lt;div id=&quot;top_controls&quot;&gt;
+  &lt;span&gt; Lives: &lt;span id=&quot;lives&quot;&gt;20&lt;/span&gt;&lt;/span&gt;
+  &lt;span&gt; Score: &lt;span id=&quot;score&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
+  &lt;span&gt; Gold: &lt;span id=&quot;gold&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
+  &lt;span&gt; Wave: &lt;span id=&quot;wave&quot;&gt;1&lt;/span&gt;&lt;/span&gt;
+  &lt;span&gt; Creep Variety: &lt;span id=&quot;creep_variety&quot;&gt;&lt;/span&gt;&lt;/span&gt;
+&lt;/div&gt;
+  
+&lt;canvas id=&quot;tower_defense&quot; width=&quot;600&quot; height=&quot;400&quot;&gt;&lt;/canvas&gt;
 
-&lt;div id=&quot;game_div&quot; style=&quot;background-color: grey; padding-left: 10px; padding-top: 20px; padding-botton: 20px;&quot;&gt;
-&lt;div style=&quot;overflow:auto&quot;&gt;
-  &lt;canvas style=&quot;float:left;&quot; id=&quot;tower_defense&quot; width=&quot;600&quot; height=&quot;400&quot;&gt;&lt;/canvas&gt;
-  &lt;div style=&quot;float:left;&quot;&gt;
-  &lt;table style=&quot;padding-left:5px&quot;&gt;
-    &lt;tr&gt;&lt;td&gt; Lives &lt;/td&gt; &lt;td id=&quot;lives&quot;&gt;20&lt;/td&gt;&lt;/tr&gt;
-    &lt;tr&gt;&lt;td&gt; Score &lt;/td&gt; &lt;td id=&quot;score&quot;&gt;0&lt;/td&gt;&lt;/tr&gt;
-    &lt;tr&gt;&lt;td&gt; Gold &lt;/td&gt; &lt;td id=&quot;gold&quot;&gt;0&lt;/td&gt;&lt;/tr&gt;
-    &lt;tr&gt;&lt;td&gt; Wave / Creep Variety &lt;/td&gt; &lt;td&gt;&lt;span id=&quot;wave&quot;&gt;1&lt;/span&gt; / &lt;span id=&quot;creep_variety&quot;&gt;Normal Creeps&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;
-    &lt;tr&gt;&lt;td&gt; Towers &lt;/td&gt; &lt;td id=&quot;towers&quot;&gt;0&lt;/td&gt;&lt;/tr&gt;
+&lt;div id=&quot;side&quot;&gt;
+&lt;div id=&quot;controls&quot;&gt;
+  &lt;table&gt;
     &lt;tr&gt;
       &lt;td&gt; &lt;button onclick=&quot;build_laser_tower();&quot; accesskey=&quot;L&quot;&gt;Build &lt;strong&gt;L&lt;/strong&gt;aser Tower&lt;/button&gt; &lt;/td&gt;
       &lt;td&gt; 50 Gold &lt;/td&gt;
@@ -29,35 +33,41 @@
     &lt;tr&gt; &lt;td&gt; Fast, ok range, low damage. &lt;/td&gt; &lt;/tr&gt;
     &lt;tr&gt;
       &lt;td&gt; &lt;button onclick=&quot;build_missile_tower();&quot; accesskey=&quot;L&quot;&gt;Build &lt;strong&gt;M&lt;/strong&gt;issile Tower&lt;/button&gt; &lt;/td&gt;
-      &lt;td&gt; 100 Gold &lt;/td&gt;
-    &lt;/tr&gt;
-    &lt;tr&gt; &lt;td&gt; Slow, long range, high damage. &lt;/td&gt;&lt;/tr&gt;
-
-      
+	  &lt;td&gt; 100 Gold &lt;/td&gt;
+	&lt;/tr&gt;
+	&lt;tr&gt; &lt;td&gt; Slow, long range, high damage. &lt;/td&gt;&lt;/tr&gt;
       &lt;td&gt; &lt;button onclick=&quot;aim_missile();&quot; accesskey=&quot;M&quot;&gt;Launch Small &lt;Strong&gt;M&lt;/strong&gt;issile&lt;/button&gt;&lt;/td&gt;
       &lt;td&gt; 50 Gold &lt;/td&gt;
     &lt;/tr&gt;
     &lt;tr&gt;&lt;td&gt; Reduce creeps by 50% of current health. &lt;/tr&gt;&lt;/td&gt;
     &lt;tr&gt;
       &lt;td&gt; &lt;button onclick=&quot;nuke_creeps();&quot; accesskey=&quot;N&quot;&gt; Launch &lt;strong&gt;N&lt;/strong&gt;uke &lt;/button&gt;&lt;/td&gt;
-      &lt;td id=&quot;nukes_left&quot;&gt; 3 remaining &lt;/td&gt;
+      &lt;td id=&quot;nukes_left&quot;&gt; 3 left &lt;/td&gt;
     &lt;/tr&gt;
     &lt;tr&gt;&lt;td&gt; Kill everything, but no loot. &lt;/td&gt;&lt;/tr&gt;
   &lt;/table&gt;
-  &lt;div style=&quot;float: left; border: solid 1px cyan;&quot;&gt;
-    &lt;div id=&quot;details&quot;&gt;&lt;/div&gt;
-    &lt;div id=&quot;details_buttons&quot;&gt;&lt;/div&gt;
-  &lt;/div&gt;
-
-  
-  &lt;/div&gt;
 &lt;/div&gt;
-&lt;div style=&quot;padding-bottom:10px; padding-top:5px;&quot;&gt;
-&lt;span&gt;&lt;strong&gt; Options &lt;/strong&gt;&lt;/span&gt;&lt;button onclick=&quot;pause_resume();&quot;&gt; Pause / Resume &lt;/button&gt;
-&lt;button onclick=&quot;reset_game();&quot;&gt;Reset Game&lt;/button&gt;&lt;/td&gt;
+
+&lt;div id=&quot;tower&quot;&gt;
+
+  &lt;table&gt;
+    &lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt; &lt;em&gt;Tower Details&lt;/em&gt; &lt;/td&gt;&lt;/tr&gt;
+    &lt;tr&gt;&lt;td&gt; Type: &lt;/td&gt;&lt;td id=&quot;tower_type&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
+    &lt;tr&gt;&lt;td&gt; Range: &lt;/td&gt;&lt;td id=&quot;tower_range&quot;&gt;&lt;/tr&gt;
+    &lt;tr&gt;&lt;td&gt; Damage: &lt;/td&gt;&lt;td id=&quot;tower_damage&quot;&gt;&lt;/tr&gt;
+    &lt;tr&gt;&lt;td&gt; Firing Rate: &lt;/td&gt;&lt;td id=&quot;tower_rate&quot;&gt;&lt;/tr&gt;
+    &lt;tr&gt;&lt;td&gt; Cost to Upgrade: &lt;/td&gt;&lt;td id=&quot;tower_upgrade_cost&quot;&gt;&lt;/tr&gt;
+    &lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;button id=&quot;tower_upgrade_button&quot;&gt;Upgrade!&lt;/button&gt;&lt;/td&gt;&lt;/tr&gt;
+  &lt;/table&gt;  
 &lt;/div&gt;
+&lt;div id=&quot;creep&quot;&gt;&lt;/div&gt;
 &lt;/div&gt;
 
+&lt;div id=&quot;bottom_controls&quot;&gt;
+  &lt;span&gt;&lt;strong&gt; Options &lt;/strong&gt;&lt;/span&gt;&lt;button onclick=&quot;pause_resume();&quot;&gt; Pause / Resume &lt;/button&gt;
+  &lt;button onclick=&quot;reset_game();&quot;&gt;Reset Game&lt;/button&gt;&lt;/td&gt;
+  &lt;/div&gt;
+&lt;/div&gt;
 
 &lt;ul&gt;
   &lt;li&gt; &lt;strong&gt; Source &lt;/strong&gt; &lt;/li&gt;</diff>
      <filename>ptd.html</filename>
    </modified>
    <modified>
      <diff>@@ -232,7 +232,6 @@ var default_set = function() {
   set.pause_state = 4;
   set.game_over_state = 5;
   set.state = set.normal_state;
-  set.state_details = &quot;&quot;;
 
   // game values
   set.creep_variety = &quot;Normal Creeps&quot;;
@@ -255,15 +254,23 @@ var SET;
 
 var fetch_ui_widgets = function() {
   var w = {};
+  // status bar widgets
   w.score = document.getElementById(&quot;score&quot;);
   w.gold = document.getElementById(&quot;gold&quot;);
-  w.towers = document.getElementById(&quot;towers&quot;);
   w.lives = document.getElementById(&quot;lives&quot;);
   w.nukes_left = document.getElementById(&quot;nukes_left&quot;);
   w.creep_variety = document.getElementById(&quot;creep_variety&quot;);
   w.wave = document.getElementById(&quot;wave&quot;);
-  w.details = document.getElementById(&quot;details&quot;);
-  w.details_buttons = document.getElementById(&quot;details_buttons&quot;);
+  
+  // tower widgets
+  w.tower = document.getElementById(&quot;tower&quot;);
+  w.tower_type = document.getElementById(&quot;tower_type&quot;);
+  w.tower_range = document.getElementById(&quot;tower_range&quot;);
+  w.tower_damage = document.getElementById(&quot;tower_damage&quot;);
+  w.tower_rate = document.getElementById(&quot;tower_rate&quot;);
+  w.tower_upgrade_cost = document.getElementById(&quot;tower_upgrade_cost&quot;);
+  w.tower_upgrade_button = document.getElementById(&quot;tower_upgrade_button&quot;);
+
   return w;
 };
 var WIDGETS;
@@ -308,11 +315,8 @@ var UIUpdater = function() {
     WIDGETS.creep_variety.innerHTML = SET.creep_variety;
     WIDGETS.score.innerHTML = SET.score;
     WIDGETS.gold.innerHTML = SET.gold;
-    WIDGETS.towers.innerHTML = SET.rendering_groups[SET.tower_render_level].length;
     WIDGETS.lives.innerHTML = SET.lives;
-    WIDGETS.nukes_left.innerHTML = SET.nukes + &quot; remaining&quot;;
-    if (SET.state_details != undefined)
-      WIDGETS.details.innerHTML = SET.state_details;
+    WIDGETS.nukes_left.innerHTML = SET.nukes + &quot; left&quot;;
   };
   assign_to_depth(uiu, SET.system_render_level);
   return uiu;
@@ -519,17 +523,25 @@ var Tower = function(settings) {
   tower.upgrade_cost = 50;
   tower.upgrade = function() {
     if (SET.gold &gt; this.upgrade_cost) {
-      alert(&quot;enough gold&quot;);
       SET.gold -= this.upgrade_cost;
       this.upgrade_cost = this.upgrade_cost * 2;
       this.damage = this.damage * 1.5;
       this.set_range(this.range * 1.1);
       this.reload_rate = this.reload_rate * 0.95;
+      this.display_stats();
     }
   }
-  tower.describe = function() {
-    return &quot;&lt;table&gt;&lt;tr&gt;&lt;td&gt;Range&lt;/td&gt;&lt;td&gt;&quot;+this.range+&quot;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Damage&lt;/td&gt;&lt;td&gt;&quot;+this.damage+&quot;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Reload Rate&lt;/td&gt;&lt;td&gt;&quot;+this.reload_rate+&quot;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Upgrade Cost&lt;/td&gt;&lt;td&gt;&quot;+this.upgrade_cost+&quot;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&quot;;
-  }
+  tower.display_stats = function() {
+    WIDGETS.tower_type.innerHTML = this.type;
+    WIDGETS.tower_range.innerHTML = this.range;
+    WIDGETS.tower_damage.innerHTML = this.damage;
+    WIDGETS.tower_rate.innerHTML = this.reload_rate;
+    WIDGETS.tower_upgrade_cost.innerHTML = this.upgrade_cost;
+    WIDGETS.tower_upgrade_button.onclick = function() {
+      tower.upgrade();
+    }
+    WIDGETS.tower.style.display = &quot;block&quot;;
+  };
 
   tower.draw = function() {
     noStroke();
@@ -734,13 +746,9 @@ var set_state_normal = function() {
   SET.state = SET.normal_state;
   SET.state_action = undefined;
   SET.state_legal = undefined;
-  SET.state_details = &quot;&quot;;
-  SET.state_details_button = undefined;
-  SET.state_details_action = undefined;
   SET.state_draw = undefined;
   SET.bg_color = SET.bg_colors.neutral;
-  WIDGETS.details_buttons.innerHTML = &quot;&quot;;
-
+  WIDGETS.tower.style.display = &quot;none&quot;;
 }
 
 var build_tower_mode = function() {
@@ -778,25 +786,16 @@ var build_laser_tower = function() {
       var gpos = pixel_to_grid(x,y);
       LaserTower(gpos.gx,gpos.gy);
       SET.gold -= 50;
-      set_state_normal(); 
+      set_state_normal();
     }
   }
 };
 
 var select_tower = function(tower) {
-  SET.state_details_button = &quot;Upgrade Tower&quot;;
-  SET.state_details_action = function() { upgrade_tower(tower.gx,tower.gy); };
   SET.state = SET.selecting_tower_state;
   KillZone(tower.x_mid,tower.y_mid,tower.range*SET.pixels_per_square);
-  SET.state_details = tower.describe();
-  
-  var elem = document.createElement(&quot;button&quot;);
-  elem.innerHTML = &quot;Upgrade!&quot;;
-  elem.onclick = function() {
-    tower.upgrade();
-    SET.state_details = tower.describe();
-  }
-  WIDGETS.details_buttons.appendChild(elem);
+  tower.display_stats();
+  WIDGETS.tower.style.display = &quot;block&quot;;
 };
 
 var aim_missile = function(x,y) {</diff>
      <filename>ptd.js</filename>
    </modified>
    <modified>
      <diff>@@ -3,10 +3,11 @@
 }
 
 div#game {
-  background-color: #888; 
-  padding-left: 10px; 
-  padding-top: 20px; 
-  padding-bottom: 20px;
+    background-color: #888; 
+    padding-left: 10px; 
+    padding-top: 20px; 
+    padding-bottom: 20px;
+    overflow: auto;
 }
 
 #game div {
@@ -17,7 +18,32 @@ div#game {
   float: left;
 }
 
+#top_controls span {
+    padding-right: 10px;
+}
+
+#bottom_controls {
+    padding-bottom:10px;
+    padding-top:5px;
+    width: 100%;
+}
+
 .error {
   background-color: 000;
   color: #f73;
+}
+
+div#side {
+    float: left;
+}
+
+#tower {
+    display: none;
+}
+
+#side table {
+    width: 96%;
+    margin-left: 10px;
+    margin-top: 10px;
+    border: solid 1px black;
 }
\ No newline at end of file</diff>
      <filename>style.css</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>1a51d01b25794f8b030192cd6444561d812efba8</id>
    </parent>
  </parents>
  <author>
    <name>Will Larson</name>
    <email>lethain@gmail.com</email>
  </author>
  <url>http://github.com/rictic/processing-tower-defense/commit/c2a937f8fb577ece29eb51aee11da648919b1290</url>
  <id>c2a937f8fb577ece29eb51aee11da648919b1290</id>
  <committed-date>2008-05-28T05:34:41-07:00</committed-date>
  <authored-date>2008-05-28T05:34:41-07:00</authored-date>
  <message>Moved scores to above canvas, rebuilt the tower data reporting table reporting mechanism to be substantially less hacky. :</message>
  <tree>d38874f2b59c44e9bff7115b21d6ae7ba918f912</tree>
  <committer>
    <name>Will Larson</name>
    <email>lethain@gmail.com</email>
  </committer>
</commit>
