text: /*
  
    P R O C E S S I N G - 0 . 0 . J S
    a port of the Processing visualization language
    
    License       : MIT 
    Developer     : John Resig: http://ejohn.org
    Web Site      : http://processingjs.org  
    Java Version  : http://processing.org
    Github Repo.  : http://github.com/jeresig/processing-js
    Bug Tracking  : http://processing-js.lighthouseapp.com
    Mozilla POW!  : http://wiki.Mozilla.org/Education/Projects/ProcessingForTheWeb
    Maintained by : Seneca: http://zenit.senecac.on.ca/wiki/index.php/Processing.js
                    Hyper-Metrix: http://hyper-metrix.com/#Processing
  
  */  
  
  
  (function(){
    
  
    // Attach Processing to the window 
    this.Processing = function Processing( aElement, aCode ){
  
      // Get the DOM element if string was passed
      if( typeof aElement == "string" ){
        aElement = document.getElementById( aElement );
      }
        
      // Build an Processing functions and env. vars into 'p'  
      var p = buildProcessing( aElement );  
  
      // Send aCode Processing syntax to be converted to JavaScript
      if( aCode ){ p.init( aCode ); }
      
      return p;
      
    };
     
    // IE Unfriendly AJAX Method
    var ajax=function( url ){
      var AJAX;
      if( AJAX = new XMLHttpRequest() ){
        AJAX.open( "GET", url, false );
        AJAX.send( null );
        return AJAX.responseText;
      }else{
        return false;
      }
    };
    
    // Automatic Initialization Method
    var init = function(){
      
      var canvas  = document.getElementsByTagName( 'canvas' ),
          datasrc = undefined;
  
      for( var i = 0; l = i < canvas.length; i++ ){
        if( datasrc = canvas[ i ].getAttribute( 'datasrc' ) ){
          Processing( canvas[ i ], ajax( datasrc ) );
        }
      }
      
    };
   
    addEventListener( 'DOMContentLoaded', function(){ init(); }, false );
   
    // Parse Processing (Java-like) syntax to JavaScript syntax with Regex
    var parse = Processing.parse = function parse( aCode, p ){
  
      // Remove end-of-line comments
      aCode = aCode.replace( /\/\/ .*\n/g, "\n" );
  
      // Weird parsing errors with %
      aCode = aCode.replace( /([^\s])%([^\s])/g, "$1 % $2" );
     
      // Simple convert a function-like thing to function
      aCode = aCode.replace( /(?:static )?(\w+ )(\w+)\s*(\([^\)]*\)\s*{)/g, function( all, type, name, args ){
        if ( name == "if" || name == "for" || name == "while" ) {
          return all;
        } else {
          return "Processing." + name + " = function " + name + args;
        }
      });
        
      // Attach import() to p{} bypassing JS command, allowing for extrernal library loading
      aCode = aCode.replace( /import \(|import\(/g, "p.Import(" );
      
      // Force .length() to be .length
      aCode = aCode.replace( /\.length\(\)/g, ".length" );
  
      // foo( int foo, float bar )
      aCode = aCode.replace( /([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4" );
      aCode = aCode.replace( /([\(,]\s*)(\w+)((?:\[\])+| )\s*(\w+\s*[\),])/g, "$1$4" );
  
      // float[] foo = new float[5];
      aCode = aCode.replace( /new (\w+)((?:\[([^\]]*)\])+)/g, function( all, name, args ){
        return "new ArrayList(" + args.slice(1,-1).split("][").join(", ") + ")";
      });
      
      // What does this do?
      aCode = aCode.replace( /(?:static )?\w+\[\]\s*(\w+)\[?\]?\s*=\s*{.*?};/g, function( all ){
        return all.replace( /{/g, "[").replace(/}/g, "]" );
      });
  
      // 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 ){
          return type + " " + name + " = 0" + sep;
        });
      }
  
      // float foo = 5;
      aCode = aCode.replace( /(?:static )?(\w+)((?:\[\])+| ) *(\w+)\[?\]?(\s*[=,;])/g, function( all, type, arr, name, sep ){
        if ( type == "return" )
          return all;
        else
          return "var " + name + sep;
      });
  
      // Fix Array[] foo = {...} to [...]
      aCode = aCode.replace( /=\s*{((.|\s)*?)};/g, function(all,data){
        return "= [" + data.replace(/{/g, "[").replace(/}/g, "]") + "]";
      });
      
      // super() is a reserved word
      aCode = aCode.replace( /super\(/g, "superMethod(" );
  
      var classes = [ "int", "float", "boolean", "string" ];
  
      function ClassReplace( all, name, extend, vars, last ){
        
        classes.push( name );
  
        var static = "";
  
        vars = vars.replace( /final\s+var\s+(\w+\s*=\s*.*?;)/g, function( all, set ){
          static += " " + name + "." + set;
          return "";
        });
  
        // Move arguments up from constructor and wrap contents with
        // a with(this), and unwrap constructor
        return "function " + name + "() {with(this){\n  " +
          ( extend ? "var __self=this;function superMethod(){extendClass(__self,arguments," + extend + ");}\n" : "" ) +
          // Replace var foo = 0; with this.foo = 0;
          // and force var foo; to become this.foo = null;
          vars
            .replace( /,\s?/g, ";\n  this." )
            .replace( /\b(var |final |public )+\s*/g, "this." )
            .replace( /\b(var |final |public )+\s*/g, "this." )
            .replace( /this.(\w+);/g, "this.$1 = null;" ) + 
            ( extend ? "extendClass(this, " + extend + ");\n" : "" ) +
            "<CLASS " + name + " " + static + ">" + ( typeof last == "string" ? last : name + "(" );
        }
  
        var matchClasses = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)\b\1\s*\(/g;
        var matchNoCon = /(?:public |abstract |static )*class (\w+)\s*(?:extends\s*(\w+)\s*)?{\s*((?:.|\n)*?)(Processing)/g;
        
        aCode = aCode.replace( matchClasses, ClassReplace );
        aCode = aCode.replace( matchNoCon, ClassReplace );
  
        var matchClass = /<CLASS (\w+) (.*?)>/, m;
        
        while ( ( m = aCode.match( matchClass ) ) ){
          
          var left        = RegExp.leftContext,
              allRest     = RegExp.rightContext,
              rest        = nextBrace( allRest ),
              className   = m[ 1 ],
              staticVars  = m[ 2 ] || "";
            
          allRest = allRest.slice( rest.length + 1 );
  
          rest = rest.replace( new RegExp("\\b" + className + "\\(([^\\)]*?)\\)\\s*{", "g"), function( all, args ){
            args = args.split( /,\s*?/ );
            
            if( args[ 0 ].match( /^\s*$/ ) ){
              args.shift();
            }
            
            var fn = "if ( arguments.length == " + args.length + " ) {\n";
              
            for ( var i = 0; i < args.length; i++ ) {
              fn += "    var " + args[ i ] + " = arguments["+ i +"];\n";
            }
              
            return fn;
          });
          
          // 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 ){
            return "ADDMETHOD(this, '" + name + "', function(" + args + ")";
          });
          
          var matchMethod = /ADDMETHOD([\s\S]*?{)/, mc;
          var methods = "";
          
          while ( ( mc = rest.match( matchMethod ) ) ){
            var prev    = RegExp.leftContext,
                allNext = RegExp.rightContext,
                next    = nextBrace(allNext);
  
            methods += "addMethod" + mc[ 1 ] + next + "});";
            
            rest = prev + allNext.slice( next.length + 1 );
          }
  
          rest = methods + rest;
          
          aCode = left + rest + "\n}}" + staticVars + allRest;
        }
  
        // Do some tidying up, where necessary
        aCode = aCode.replace( /Processing.\w+ = function addMethod/g, "addMethod" );
        
        function nextBrace( right ) {
  
          var rest      = right,
              position  = 0,
              leftCount = 1,
              rightCount = 0;
          
          while( leftCount != rightCount ) {
          
          var nextLeft  = rest.indexOf( "{" ),
              nextRight = rest.indexOf( "}" );
          
          if( nextLeft < nextRight && nextLeft != - 1 ) {
  
            leftCount++;
            rest = rest.slice( nextLeft + 1 );
            position += nextLeft + 1;
  
          }else{
  
            rightCount++;
            rest = rest.slice( nextRight + 1 );
            position += nextRight + 1;
  
          }
          
        }
          
        return right.slice( 0, position - 1 );
      }
  
      // Handle (int) Casting
      aCode = aCode.replace( /\(int\)/g, "0|" );
  
      // Remove Casting
      aCode = aCode.replace( new RegExp("\\((" + classes.join("|") + ")(\\[\\])?\\)", "g"), "" );
      
      // Convert 3.0f to just 3.0
      aCode = aCode.replace( /(\d+)f[^a-zA-Z0-9]/g, "$1" );
  
      // Force numbers to exist //
      //aCode = aCode.replace(/([^.])(\w+)\s*\+=/g, "$1$2 = ($2||0) +");
  
  //!  // Force characters-as-bytes to work --> Ping: Andor
      aCode = aCode.replace(/('[a-zA-Z0-9]')/g, "$1.charCodeAt(0)");
  
      // Convert #aaaaaa into color
      aCode = aCode.replace(/#([a-f0-9]{6})/ig, function(m, hex){
        var num = toNumbers(hex);
        return "DefaultColor(" + num[0] + "," + num[1] + "," + num[2] + ")";
      });
  
      function toNumbers( str ){
        var ret = [];
        
        str.replace( /(..)/g, function( str ){
          ret.push( parseInt( str, 16 ) );
        });
        
        return ret;
      }
  
      return aCode;
  
    };
  
  
    // Attach Processing functions to 'p' 
    function buildProcessing( curElement ){
                
      // Create the 'p' object
      var p = {};
      
      // Set Processing defaults / environment variables
      p.name            = 'Processing.js Instance';
      p.PI              = Math.PI;
      p.TWO_PI          = 2 * p.PI;
      p.HALF_PI         = p.PI / 2;
      p.P3D             = 3;
      p.CORNER          = 0;
      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;
      p.focused         = true;
  
      // KeyCode table  
      p.CENTER  = 88888880;
      p.CODED   = 88888888;
      p.UP      = 88888870;
      p.RIGHT   = 88888871;
      p.DOWN    = 88888872;
      p.LEFT    = 88888869;
      
  //! // Description required...
      p.codedKeys = [ 69, 70, 71, 72  ];
  
      // "Private" variables used to maintain state
      var curContext      = curElement.getContext( "2d" ),
          online          = true,
          doFill          = true,
          doStroke        = true,
          loopStarted     = false,
          hasBackground   = false,
          doLoop          = true,
          looping         = 0,
          curRectMode     = p.CORNER,
          curEllipseMode  = p.CENTER,
          inSetup         = false,
          inDraw          = false,
          curBackground   = "rgba( 204, 204, 204, 1 )",
          curFrameRate    = 1000,
          curMsPerFrame   = 1,
          curShape        = p.POLYGON,
          curShapeCount   = 0,
          curvePoints     = [],
          curTightness    = 0,
          opacityRange    = 255,
          redRange        = 255,
          greenRange      = 255,
          blueRange       = 255,
          pathOpen        = false,
          mousePressed    = false,
          keyPressed      = false,
          curColorMode    = p.RGB;
          curTint         = - 1,
          curTextSize     = 12,
          curTextFont     = "Arial",
          getLoaded       = false,
          start           = ( new Date ).getTime();
  
      var firstX,
          firstY,
          secondX,
          secondY,
          prevX,
          prevY;
      
      // Store a line for println(), print() handline
      p.ln = "";
      
      // Glyph path storage for textFonts
      p.glyphTable = {};
      
      // Global vars for tracking mouse position
      p.pmouseX     = 0;
      p.pmouseY     = 0;
      p.mouseX      = 0;
      p.mouseY      = 0;
      p.mouseButton = 0;
      p.mouseDown   = false;
  
      // Undefined event handlers to be replaced by user when needed
      p.mouseClicked = undefined;
      p.mouseDragged = undefined;
      p.mouseMoved = undefined;
      p.mousePressed = undefined;
      p.mouseReleased = undefined;
      p.keyPressed = undefined;
      p.keyReleased = undefined;
      p.draw = undefined;
      p.setup = undefined;
  
      // The height/width of the canvas
      p.width  = curElement.width  - 0;
      p.height = curElement.height - 0;
  
      // The current animation frame
      p.frameCount = 0;            
      
      
  
      ////////////////////////////////////////////////////////////////////////////
      // Array handling
      ////////////////////////////////////////////////////////////////////////////    
      
      p.splitTokens = function( str, tokens ){
  
        if( arguments.length == 1 ){
          tokens = "\n\t\r\f ";
        }
  
        tokens = "[" + tokens + "]";
  
        var ary = new Array();
        var index = 0;
        var pos = str.search( tokens );
  
        while( pos >= 0 ){
          if (pos == 0){
             str = str.substring( 1 );
          }else{
            ary[ index ] = str.substring( 0, pos );
            index++;
            str = str.substring( pos );
          }
          pos = str.search( tokens );
        }
  
        if( str.length > 0 ){
           ary[ index ] = str;
        }
  
        if( ary.length == 0 ){
            ary = undefined;
        }
  
        return ary;
      }
  
    
      
      p.append = function( array, element ){
        array[ array.length ] = element;
        return array;
      }
      
      p.concat = function concat( array1, array2 ){
        return array1.concat( array2 );
      }
  
      p.splice = function( array, value, index ){
  
        if(array.length == 0 && value.length == 0){
          return array;
        };
  
        if( value instanceof Array ){
          for( var i = 0, j = index; i < value.length; j++, i++ ){
           array.splice( j, 0, value[ i ] );
          }
        }else{
          array.splice( index, 0, value );
        };
        
        return array;
        
      }; 
  
      p.subset = function( array, offset, length ){
        if(arguments.length == 2){
          return p.subset( array, offset, array.length - offset );
        }else if( arguments.length == 3 ){
          return array.slice( offset, offset + length );
        }
      };
  
      p.concat = function concat( array1, array2 ){ return array1.concat( array2 ) };
      
      p.join = function join( array, seperator ){ return array.join( seperator ) };
      
      p.shorten = function( ary ){
      
        var newary = new Array();
  
        // copy array into new array
        var len = ary.length;     
        for( var i = 0; i < len; i++ ){
          newary[ i ] = ary[ i ];
        }
  
        newary.pop();
  
        return newary;
      }
  
    
      p.expand = function( ary, newSize ){
  
        var newary = new Array();
        
        var len = ary.length
        for( var i = 0; i < len; i++ ){
            newary[ i ] = ary[ i ];
        }
        
        if( arguments.length == 1 ){
          
          // double size of array
          newary.length *= 2;
          
        }else if( arguments.length == 2 ){
          
          // size is newSize
          newary.length = newSize;
          
        }
        
        return newary;
      }
  
  
  
      p.ArrayList = function ArrayList( size, size2, size3 ){
      
        var array = new Array( 0 | size );
        
        if( size2 ){
          
          for( var i = 0; i < size; i++ ){
            
            array[ i ] = [];
  
            for( var j = 0; j < size2; j++ ){
              var a = array[ i ][ j ] = size3 ? new Array( size3 ) : 0 ;  
              for( var k = 0; k < size3; k++ ){ a[ k ] = 0; }
            }
            
          }
          
        }else{
          
          for( var i = 0; i < size; i++ ){ array[ i ] = 0; }        
        }
        
        array.get     = function( i    ){ return this[ i ];           };
        array.add     = function( item ){ return this.push( item );   };
        array.size    = function(      ){ return this.length;         };      
        array.clear   = function(      ){ this.length = 0;            };
        array.remove  = function( i    ){ return this.splice( i, 1 ); };
        array.isEmpty = function(      ){ return !this.length;        };
        array.clone   = function(      ){
                                          var a = new ArrayList( size );
                                          for( var i = 0; i < size; i++ ){
                                            a[ i ] = this[ i ];
                                          }
                                          return a;
                                        };
        
        return array;
      };
  
  
  
      ////////////////////////////////////////////////////////////////////////////
      // Color functions
      ////////////////////////////////////////////////////////////////////////////
      
      // !! WARNING: brightness() & saturation() not working with HSB colors
      p.brightness = function brightness(){
        return p.color( redRange, greenRange, blueRange );
      }
  
      p.saturation = function saturation( color ){
        return  p.color( ( 126 / 255 ) * redRange, ( 126 / 255 ) * greenRange, ( 126 / 255 ) * blueRange );
      }
  
      p.hue = function hue(){
        return p.color( 0 * redRange, 0 * greenRange, 0 * blueRange );
      }
       
  
      // 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 ) {
        var aColor = "";
        
        if ( arguments.length == 3 ) {
        
          aColor = p.color( aValue1, aValue2, aValue3, opacityRange );
        } else if ( arguments.length == 4 ) {
          var a = aValue4 / opacityRange;
          a = isNaN(a) ? 1 : a;
  
          if ( curColorMode == p.HSB ) {
            var rgb = HSBtoRGB(aValue1, aValue2, aValue3);
            var r = rgb[0], g = rgb[1], b = rgb[2];
          } else {
            var r = getColor(aValue1, redRange);
            var g = getColor(aValue2, greenRange);
            var b = getColor(aValue3, blueRange);
          }
  
          aColor = "rgba(" + r + "," + g + "," + b + "," + a + ")";
        } else if ( typeof aValue1 == "string" ) {
          aColor = aValue1;
  
          if ( arguments.length == 2 ) {
            var c = aColor.split(",");
            c[3] = (aValue2 / opacityRange) + ")";
            aColor = c.join(",");
          }
        } else if ( arguments.length == 2 ) {
          aColor = p.color( aValue1, aValue1, aValue1, aValue2 );
        } else if ( typeof aValue1 == "number" && aValue1 < 256 && aValue1 >= 0) {
          aColor = p.color( aValue1, aValue1, aValue1, opacityRange );
        } else if ( typeof aValue1 == "number" ) {
          var intcolor = 0;
          if( aValue1 < 0 ){
            intcolor = 4294967296 - ( aValue1 * -1 );
          }else{
            intcolor = aValue1;
          }
          var ac = Math.floor((intcolor % 4294967296) / 16777216);
          var rc = Math.floor((intcolor % 16777216) / 65536);
          var gc = Math.floor((intcolor % 65536) / 256);
          var bc = intcolor % 256;
            
          aColor = p.color( rc, gc, bc, ac );
        } else {
          aColor = p.color( redRange, greenRange, blueRange, opacityRange );
        }
  
        // HSB conversion function from Mootools, MIT Licensed
        function HSBtoRGB(h, s, b) {
          h = (h / redRange) * 360;
          s = (s / greenRange) * 100;
          b = (b / blueRange) * 100;
          var br = Math.round(b / 100 * 255);
          if (s == 0){
            return [br, br, br];
          } else {
            var hue = h % 360;
            var f = hue % 60;
            var p = Math.round((b * (100 - s)) / 10000 * 255);
            var q = Math.round((b * (6000 - s * f)) / 600000 * 255);
            var t = Math.round((b * (6000 - s * (60 - f))) / 600000 * 255);
            switch (Math.floor(hue / 60)){
              case 0: return [br, t, p];
              case 1: return [q, br, p];
              case 2: return [p, br, t];
              case 3: return [p, q, br];
              case 4: return [t, p, br];
              case 5: return [br, p, q];
            }
          }
        }
      
        function getColor( aValue, range ) {
          return Math.round(255 * (aValue / range));
        }
        
        return aColor;
      }
      
      p.red   = function( aColor ){ return parseInt( verifyChannel( aColor ).slice( 5 ) ); };
      p.green = function( aColor ){ return parseInt( verifyChannel( aColor ).split( "," )[ 1 ] ); };
      p.blue  = function( aColor ){ return parseInt( verifyChannel( aColor ).split( "," )[ 2 ] ); };
      p.alpha = function( aColor ){ return parseInt( parseFloat( verifyChannel( aColor ).split( "," )[ 3 ] ) * 255 ); };
  
      function verifyChannel( aColor ){ 
        if( aColor.constructor == Array ){    
          return aColor;
        } else {
          return p.color( aColor );
        } 
      }
      
      p.lerpColor = function lerpColor( c1, c2, amt ){
          
        // Get RGBA values for Color 1 to floats
        var colors1 = p.color( c1 ).split( "," );
        var r1 =   parseInt( colors1[ 0 ].split( "(" )[ 1 ] ); 
        var g1 =   parseInt( colors1[ 1 ] );
        var b1 =   parseInt( colors1[ 2 ] );
        var a1 = parseFloat( colors1[ 3 ].split( ")" )[ 0 ] );
            
        // Get RGBA values for Color 2 to floats
        var colors2 = p.color( c2 ).split( "," );
        var r2 =   parseInt( colors2[ 0 ].split( "(" )[ 1 ] ); 
        var g2 =   parseInt( colors2[ 1 ] );
        var b2 =   parseInt( colors2[ 2 ] );
        var a2 = parseFloat( colors2[ 3 ].split( ")" )[ 0 ] );            
                          
        // Return lerp value for each channel, INT for color, Float for Alpha-range
        var r =   parseInt( p.lerp( r1, r2, amt ) );
        var g =   parseInt( p.lerp( g1, g2, amt ) );
        var b =   parseInt( p.lerp( b1, b2, amt ) );
        var a = parseFloat( p.lerp( a1, a2, amt ) );
        
        return aColor = "rgba("+ r +","+ g +","+ b +","+ a +")";
     
      }
  
      // Forced default color mode for #aaaaaa style
      p.DefaultColor = function( aValue1, aValue2, aValue3 ){
        var tmpColorMode = curColorMode;
        curColorMode = p.RGB;
        var c = p.color(aValue1 / 255 * redRange, aValue2 / 255 * greenRange, aValue3 / 255 * blueRange );
        curColorMode = tmpColorMode;
        return c;
      }
      
      p.colorMode = function colorMode( mode, range1, range2, range3, range4 ){
        curColorMode = mode;
        if( arguments.length >= 4 ){ redRange     = range1; greenRange = range2; blueRange  = range3; }
        if( arguments.length == 5 ){ opacityRange = range4; }
        if( arguments.length == 2 ){ p.colorMode( mode, range1, range1, range1, range1 ); }    
      };
      
  
      ////////////////////////////////////////////////////////////////////////////
      // Canvas-Matrix manipulation
      ////////////////////////////////////////////////////////////////////////////
  
      p.translate   = function translate( x, y ){ curContext.translate( x, y );   };    
      p.scale       = function scale( x, y )    { curContext.scale( x, y || x );  };    
      p.rotate      = function rotate( aAngle ) { curContext.rotate( aAngle );    };    
      p.pushMatrix  = function pushMatrix()     { curContext.save();              };
      p.popMatrix   = function popMatrix()      { curContext.restore();           };
      p.ortho       = function ortho(){};
  
  
      
      ////////////////////////////////////////////////////////////////////////////
      //Time based functions
      ////////////////////////////////////////////////////////////////////////////
  
      p.year    = function year()  { return ( new Date ).getYear() + 1900;   };
      p.month   = function month() { return ( new Date ).getMonth();         };
      p.day     = function day()   { return ( new Date ).getDay();           };
      p.hour    = function hour()  { return ( new Date ).getHours();         };
      p.minute  = function minute(){ return ( new Date ).getMinutes();       };
      p.second  = function second(){ return ( new Date ).getSeconds();       };
      p.millis  = function millis(){ return ( new Date ) .getTime() - start; };
      
      p.noLoop  = function noLoop(){ doLoop = false; };
           
      p.redraw = function redraw(){
        if( hasBackground ){ p.background(); }
        p.frameCount++;      
        inDraw = true;
        p.pushMatrix();
        p.draw();
        p.popMatrix();
        inDraw = false;      
      };
      
      p.loop = function loop(){
        
        if( loopStarted ){ return; }
        
        looping = setInterval( function(){
           
            try {
                        try{
                          p.focused = document.hasFocus();
                        }catch(e){}
                        p.redraw();
                }
            catch( e ){
                        clearInterval( looping );
                        throw e;
                      }
        }, curMsPerFrame );
        
        loopStarted = true;
        
      };
      
      p.frameRate = function frameRate( aRate ){
        curFrameRate = aRate;
        curMsPerFrame = 1000 / curFrameRate;
      };
  
      p.exit = function exit(){
        clearInterval( looping );
      };
      
      
      
      ////////////////////////////////////////////////////////////////////////////
      // MISC functions
      ////////////////////////////////////////////////////////////////////////////
      p.cursor = function(mode){ document.body.style.cursor=mode; }
      p.link = function( href, target ) { window.location = href; };
      p.beginDraw = function beginDraw(){};
      p.endDraw = function endDraw(){};
      
      p.ajax = ajax;
      
      // Imports an external Processing.js library
      p.Import = function Import( lib ){
        eval( p.ajax( lib ) );
      }
          
      p.disableContextMenu = function disableContextMenu(){
        curElement.addEventListener( 'contextmenu', function( e ){
          e.preventDefault();
          e.stopPropagation();
        }, false );
      }
      
      
  
      ////////////////////////////////////////////////////////////////////////////
      // Binary Functions
      ////////////////////////////////////////////////////////////////////////////
  
      p.unbinary = function unbinary( binaryString ){
  	    var binaryPattern = new RegExp("^[0|1]{8}$");
  	    var addUp = 0;
  
  	    if( isNaN( binaryString ) ){
  		    throw "NaN_Err";
  	    }else{
  		    if( arguments.length == 1 || binaryString.length == 8 ){
  			    if( binaryPattern.test( binaryString ) ){
  				    for( i = 0; i < 8; i++ ){
  					    addUp += ( Math.pow( 2, i ) * parseInt( binaryString.charAt( 7 - i ) ) );
  				    }
  				    return addUp + "";
  			    }else{
  				    throw "notBinary: the value passed into unbinary was not an 8 bit binary number";
  			    };
  		    }else{
  			    throw "longErr";
  		    };
  
  	    };
  	    
  	    return addUp;
      }
  
      p.nfs = function( num, left, right){
        var str;
        // array handling
        if (typeof num == "object"){
          str = new Array();
          len = num.length;
          for(var i=0; i < len; i++){
            str[i] = p.nfs(num[i], left, right);
          }
        }
        else if (arguments.length == 3){
          var negative = false;
          if (num < 0)
            negative = true;
            
          str = "" + Math.abs(num);
          var digits = ("" + Math.floor(Math.abs(num))).length;
          var count = left - digits;
          while (count > 0){
            str = "0" + str;
            count--;
          }
          // get the number of decimal places, if none will be -1
          var decimals = ("" + Math.abs(num)).length - digits - 1;
          if (decimals == -1 && right > 0)
            str = str + ".";
          if (decimals != -1)
            count = right - decimals;
          else if (decimals == -1 && right > 0){
            count = right;
          }
          else
            count = 0;
          while (count > 0){
            str = str + "0";
            count--;
          }
          str = (negative ? "-" : " ") + str;
        }
        else if (arguments.length == 2){
          str = p.nfs(num, left, 0);
        }
        return str;
      }
      
      //function i use to convert RGB to hex values
      p.RGB2HTML = function RGB2HTML(red, green, blue) {
  	    var char = "0123456789ABCDEF";
  	    return String(char.charAt(Math.floor(rgb / 16))) + String(char.charAt(rgb - (Math.floor(rgb / 16) * 16)));
      }
  
      //function i use to convert decimals to a padded hex value
      p.decimalToHex = function decimalToHex(d, padding) {
  	    //if there is no padding value added, default padding to 8  else  go into while statement.
  	    padding = typeof (padding) === "undefined" || padding === null ? padding = 8 : padding;
  	    var hex = Number(d).toString(16);
  
  	    while (hex.length < padding) {
  		    hex = "0" + hex;
  	    }
  	    return hex;
      }
  
      //regExp i made to pattern match rgba and extract it's values
      p.colorRGB = function colorRGB(col) {
  	    patt = /^rgba?\((\d{1,3}),(\d{1,3}),(\d{1,3}),?(\d{0,3})\)$/i;  //grouped \d{1,3} with ( ) so they can be referenced w\ $1-$4
  	    var str2 = col.replace(patt, "#$4,$1,$2,$3");
  
  	    al = col.replace(patt, "$4");
  	    reD = col.replace(patt, "$1");
  	    gree = col.replace(patt, "$2");
  	    blu = col.replace(patt, "$3");
  
  	    return ("" + Number(al).toString(16) + Number(reD).toString(16) + Number(gree).toString(16) + Number(blu).toString(16)).toUpperCase();
      }
  
      p.hex = function hex(decimal, len) {
  	    var hexadecimal = "";
  
  	    var patternRGBa = /^rgba?\((\d{1,3}),(\d{1,3}),(\d{1,3}),?(\d{0,3})\)$/i;  //match rgba(20,20,20,0) or rgba(20,20,20)
  	    var patternDigits = /^\d+$/;
  	    //**************************   dealing with 2 parameters   *************************************************
  	    if (arguments.length == 2) {
  		    if (patternDigits.test(decimal)) {
  			    hexadecimal = p.decimalToHex(decimal, len);
  		    }
  		    else if (patternRGBa.test(decimal)) //check to see if it's an rgba color
  		    {
  			    hexadecimal = p.colorRGB(decimal);
  			    hexadecimal = hexadecimal.substring(hexadecimal.length - len, hexadecimal.length);
  		    }
  	    }
  	    else if (arguments.length == 1) //****************   dealing with 1 parameter  ********************************
  	    {
  		    if (patternDigits.test(decimal)) {      //check to see if it's a decimal
  			    hexadecimal = p.decimalToHex(decimal);
  		    }
  		    else if (patternRGBa.test(decimal)) //check to see if it's an rgba color
  		    {
  			    hexadecimal = p.colorRGB(decimal);
  		    }
  		    else if (decimal.indexOf("#") == 0) //check to see if it's hex color in format #ffffff
  		    {
  			    if (decimal.length < 7) {
  				    throw "Not Hex format: the value passed into hex was not in the format #FFFFFF";
  			    }
  			    else {
  				    decimal = (decimal.slice(1)).toUpperCase();
  				    while (decimal.length < 8) {
  					    decimal = "FF" + decimal;
  				    }
  				    hexadecimal = decimal;
  			    }
  		    }
  	    }
  	    return hexadecimal;
      }
      
      p.unhex = function( str ){
          var value = 0,
              multiplier = 1,
              num = 0;
          
          var len = str.length - 1;
          for (var i = len ; i >= 0; i--){
              try{
                  switch(str[i]){
                      case "0": num = 0; break;
                      case "1": num = 1; break;
                      case "2": num = 2; break;
                      case "3": num = 3; break;
                      case "4": num = 4; break;
                      case "5": num = 5; break;
                      case "6": num = 6; break;
                      case "7": num = 7; break;
                      case "8": num = 8; break;
                      case "9": num = 9; break;
                      case "A":
                      case "a": num = 10; break;
                      case "B":
                      case "b": num = 11; break;
                      case "C": 
                      case "c": num = 12; break;
                      case "D":
                      case "d": num = 13; break;
                      case "E":
                      case "e": num = 14; break;
                      case "F":
                      case "f": num = 15; break;
                      default:return 0; break;
                  }
                  value += num * multiplier;
                  multiplier *= 16;
              }catch(e){;}
              // correct for int overflow java expectation
              if (value > 2147483647)
              {
                  value -= 4294967296;
              }  
          }
          return value;
        }
  
  
      // Load a file or URL into strings     
      p.loadStrings = function loadStrings( url ){
        return p.ajax( url ).split( "\n" );              
      };
  
      p.nf = function( num, pad ){
        var str = "" + num;
        while ( pad - str.length ){
          str = "0" + str;
        }
        return str;
      };
  
      p.nfp = function nfp(Value, pad, right){
  	    var str = String(Value);
  
  	    if (arguments.length < 3){	//check if it's 2 arguments
  		    if (Value > 0) {
  			    while (str.length < pad)					
  				    str = "0" + str;
  		
  			    str = "+" + str;
  			    return str;
  		    }
  		    else {
  			    str = str.slice(1);  //used to remove the '-' infront of the original number.
  			    while (str.length < pad)					
  				    str = "0" + str;
  		
  			    str = "-" + str;
  			    return str;
  		    }
  	    }
  	    else if (arguments.length == 3) {  //check if it's 3 arguments 
  		    var decimalPos = str.indexOf('.');
  		    if (Value > 0) {                    
  			    var strL = str.slice(0,decimalPos);   //store #'s to left of decimal into strL
  			    var strR = str.slice(decimalPos+1,str.length);  //store #'s to right of decimal into strR
  		
  			    while (strL.length < pad)   //pad to left of decimal on positive #'s
  				    strL = "0" + strL;
  			
  			    strL = "+" + strL;
  		
  			    while (strR.length < right)  //pad to right of decimal on positive #'s
  				    strR = strR + "0";
  		
  			    return strL+"."+strR;
  		    }
  		    else {
  			    var strL = str.slice(1,decimalPos);   //store #'s to left of decimal into strL
  			    var strR = str.slice(decimalPos+1,str.length);  //store #'s to right of decimal into strR
  		
  			    while (strL.length < pad)  //pad to left of decimal on negative #'s
  				    strL = "0" + strL;
  			
  			    strL = "-" + strL;
  		
  			    while (strR.length < right)  //pad to right of decimal on negative #'s
  				    strR = strR + "0";
  		
  			    return strL+"."+strR;
  		    }
  	    }
      }
  
      ////////////////////////////////////////////////////////////////////////////
      // String Functions
      ////////////////////////////////////////////////////////////////////////////
  
      String.prototype.replaceAll = function( re, replace ){
        return this.replace( new RegExp( re, "g" ), replace );
      };
  
      p.match = function( str, regexp ){
        return str.match( regexp );
      }  
          
      // Returns a line to lnPrinted() for user handling 
      p.lnPrinted = function lnPrinted(){};
      p.printed   = function printed()  {};  
      
      // Event to send output to user control function print()/println()
      p.println = function println(){
        
        // Not working on Safari :( find work around!
        if( arguments.callee.caller ){
        
          var Caller = arguments.callee.caller.name.toString();
          
          if( arguments.length > 1 ){
  
            Caller != "print"        ?
              p.ln  = arguments      :
              p.ln  = arguments[ 0 ] ;
  
          }else{
  
              p.ln  = arguments[ 0 ] ;
          }
          
          //Returns a line to lnPrinted() for user error handling/debugging
          Caller == "print"          ?        
            p.printed( arguments )   :
            p.lnPrinted()            ;
          
        }
        
      };    
  
      // Converts a number to a string
      p.str = function str( aNumber ){ return aNumber+''; }   
      
      p.print = function print(){ p.println(arguments[ 0 ] ) };
      
      p.char = function char( key ){ return key; };
      
      
      
      ////////////////////////////////////////////////////////////////////////////
      // Math functions
      ////////////////////////////////////////////////////////////////////////////
      
      p.sq      = function sq     ( aNumber             ){ return aNumber * aNumber;                       };
      p.sqrt    = function sqrt   ( aNumber             ){ return Math.sqrt( aNumber );                    };
      p.int     = function int    ( aNumber             ){ return Math.floor( aNumber );                   };
      p.min     = function min    ( aNumber, aNumber2   ){ return Math.min( aNumber, aNumber2 );           };
      p.max     = function max    ( aNumber, aNumber2   ){ return Math.max( aNumber, aNumber2 );           };
      p.floor   = function floor  ( aNumber             ){ return Math.floor( aNumber );                   };
      p.float   = function float  ( aNumber             ){ return parseFloat( aNumber );                   };
      p.ceil    = function ceil   ( aNumber             ){ return Math.ceil( aNumber );                    };    
      p.round   = function round  ( aNumber             ){ return Math.round( aNumber );                   };
      p.lerp    = function lerp   ( value1, value2, amt ){ return ( ( value2 - value1 ) * amt ) + value1;  };
      p.abs    = function abs     ( aNumber             ){ return Math.abs( aNumber );                     };
      p.cos     = function cos    ( aNumber             ){ return Math.cos( aNumber );                     };
      p.sin     = function sin    ( aNumber             ){ return Math.sin( aNumber );                     };
      p.pow     = function pow    ( aNumber, aExponent  ){ return Math.pow( aNumber, aExponent );          };
      p.sqrt    = function sqrt   ( aNumber             ){ return Math.sqrt( aNumber );                    };
      p.atan2   = function atan2  ( aNumber, aNumber2   ){ return Math.atan2( aNumber, aNumber2 );         };
      p.radians = function radians( aAngle              ){ return ( aAngle / 180 ) * p.PI;                 };
  
      p.dist = function dist( x1, y1, x2, y2 ){
        return Math.sqrt( Math.pow( x2 - x1, 2 ) + Math.pow( y2 - y1, 2 ) );
      };
  
      p.map = function map( value, istart, istop, ostart, ostop ){
        return ostart + ( ostop - ostart ) * ( ( value - istart ) / ( istop - istart ) );
      };
      
      p.mag = function( a, b, c ){
        if( arguments.length == 2 ){
          return Math.sqrt( a*a + b*b );
        }else if( arguments.length == 3 ){
          return Math.sqrt( a*a + b*b + c*c );
        };
      };
  
      p.Random = function(){
  
        var haveNextNextGaussian = false,
            nextNextGaussian;
  
        this.nextGaussian = function(){
          
          if( haveNextNextGaussian ){
          
            haveNextNextGaussian = false;
            return nextNextGaussian;
          
          }else{
            
            var v1, v2, s;
            do{ 
                v1 = 2 * p.random( 1 ) - 1;   // between -1.0 and 1.0
                v2 = 2 * p.random( 1 ) - 1;   // between -1.0 and 1.0
                s = v1 * v1 + v2 * v2;
            }
            while( s >= 1 || s == 0 );
            
            var multiplier = Math.sqrt( - 2 * Math.log( s ) / s );
            nextNextGaussian = v2 * multiplier;
            haveNextNextGaussian = true;
  
            return v1 * multiplier;
          
          }
          
        };
        
      };
  
  //! This can't be right... right?
      p.byte     = function byte( aNumber               ){ return aNumber || 0;                           };
  
      p.norm     = function norm( aNumber, low, high   ){
        var range = high-low;
        return ( ( 1 / range ) * aNumber ) - ( ( 1 / range ) * low );
      };        
      
      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 ){
        return arguments.length >= 2  ?
          PerlinNoise_2D( x, y, z )    :
          PerlinNoise_3D( x, x, z )    ;
      };
  
      function Noise( x, y ){
        var n = x + y * 57;
        n = ( n << 13 ) ^ n;
        return Math.abs( 1.0 - ( ( ( n * ( ( n * n * 15731 ) + 789221 ) + 1376312589 ) & 0x7fffffff ) / 1073741824.0 ) );
      };
  
      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,
            sides   = ( Noise( x - 1, y ) + Noise( x + 1, y ) + Noise( x, y - 1 ) + Noise( x, y + 1 ) ) / 8,
            center  = Noise( x, y ) / 4;
        return corners + sides + center;
      };
  
      function InterpolatedNoise( x, y ){
  
        var integer_X    = Math.floor( x );
        var fractional_X = x - integer_X;
  
        var integer_Y    = Math.floor( y );
        var fractional_Y = y - integer_Y;
  
        var v1 = SmoothedNoise( integer_X,     integer_Y     ),
            v2 = SmoothedNoise( integer_X + 1, integer_Y     ),
            v3 = SmoothedNoise( integer_X,     integer_Y + 1 ),
            v4 = SmoothedNoise( integer_X + 1, integer_Y + 1 );
  
        var i1 = Interpolate( v1, v2, fractional_X ),
            i2 = Interpolate( v3, v4, fractional_X );
  
        return Interpolate( i1, i2, fractional_Y );
        
      }
  
  
      function PerlinNoise_2D( x, y ){
  
          var total = 0,
              p     = 0.25,
              n     = 3;
  
          for( var i = 0; i <= n; i++ ){
            var frequency = Math.pow( 2, i );
            var amplitude = Math.pow( p, i );
            total += InterpolatedNoise( x * frequency, y * frequency ) * amplitude;
          }
  
          return total;
      }
  
      function Interpolate( a, b, x ){
        var ft   = x * p.PI;
        var f   = (1 - Math.cos( ft ) ) * .5;
        return  a * ( 1 - f ) + b * f;
      }
     
      p.constrain = function constrain( aNumber, aMin, aMax ){
        return Math.min( Math.max( aNumber, aMin ), aMax );
      };
            
      p.degrees = function degrees( aAngle ){
        aAngle = ( aAngle * 180 ) / p.PI;  
        if (aAngle < 0) {aAngle = 360 + aAngle}    
        return aAngle;
      };
      
      // Changes the size of the Canvas ( this resets context properties like 'lineCap', etc.
      p.size = function size( aWidth, aHeight ){
      
        var props = { fillStyle   : curContext.fillStyle,
                      strokeStyle : curContext.strokeStyle,
                      lineCap     : curContext.lineCap
                    } // More to be added...
        
        curElement.width = p.width = aWidth;
        curElement.height = p.height = aHeight;
  
        for( var i in props ){ curContext[ i ] = props[ i ] };
      };
      
      // PVector instantiation
      p.PVector = function PVector(){ return new vectorOps( arguments ) };
      
      // PVector method translation
      p.PVector.add = PVectorAdd;
      p.PVector.sub = PVectorSub;
      p.PVector.mult = PVectorMult;
      p.PVector.div = PVectorDiv;
      p.PVector.dist = PVectorDist;
      p.PVector.angleBetween = PVectorAngle;
      
      // PVector methods
      function PVectorAdd(){
        var a = arguments;
        return p.PVector( a[0].x + a[1].x, a[0].y + a[1].y, a[0].z + a[1].z );
      }
  
      function PVectorSub(){
  	    var a = arguments;
        return p.PVector( a[0].x - a[1].x, a[0].y - a[1].y,a[0].z - a[1].z );
      }
  
      function PVectorMult(){    
  	    if( typeof arguments[1] == 'number' ){
  		    var a = arguments;
  		    return p.PVector( a[0].x * a[1], a[0].y * a[1], a[0].z * a[1] );
  	    }else if( typeof arguments[1] == 'object' ){
  		    var a = arguments;
  		    return p.PVector( a[0].x * a[1].x, a[0].y * a[1].y, a[0].z * a[1].z );
  	    }
      }
  
      function PVectorDiv(){
  	    if( typeof arguments[1] == 'number' ){
  		    var a = arguments;
  		    return p.PVector( a[0].x / a[1], a[0].y / a[1], a[0].z / a[1] );
  	    }
  	    else if ( typeof (arguments[1]) == 'object' ){
  		    var a = arguments;      
          return p.PVector( a[0].x / a[1].x, a[0].y / a[1].y, a[0].z / a[1].z );
  	    }
      }
  
      function PVectorDist(){
  	    var v1 = new p.PVector();
  	    var v2 = new p.PVector();
  	    v1 = arguments[0];
  	    v2 = arguments[1];
  	    return v1.dist(v2);
      }
  
      function PVectorAngle(v1, v2){
  	    return Math.acos( v1.dot(v2) / (v1.mag()*v2.mag()) );
      }
  
      // Common vector operations for PVector
      function vectorOps(){
  
        arguments = arguments[0];
        this.x = arguments[ 0 ] || 0;
        this.y = arguments[ 1 ] || 0;
        this.z = arguments[ 2 ] || 0;
        
        this.set = function(){
          if (arguments.length == 1){
            var vArr = arguments[0];
            this.set(arguments[0].x || vArr[0], arguments[0].y || vArr[1], arguments[0].z || vArr[2]);
          }else{
            this.x = arguments[0];
            this.y = arguments[1];
            this.z = arguments[2];
          };
        };
  	    
  	    this.get = function get(){ return p.PVector( this.x, this.y, this.z ) };
  	    this.mag = function mag(){ return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ) };
        this.add = function(){
            if( arguments.length == 3 ){
              this.x += arguments[0];
              this.y += arguments[1];
              this.z += arguments[2];
            }else if( arguments.length == 1 ){
              this.x += arguments[0].x;
              this.y += arguments[0].y;
              this.z += arguments[0].z;
            };
        };
        this.sub = function(){
            if( arguments.length == 3 ){
  		        this.x -= arguments[0];
  		        this.y -= arguments[1];
  		        this.z -= arguments[2];
    	      }else if( arguments.length == 1 ){
  		        this.x -= arguments[0].x;
  		        this.y -= arguments[0].y;
  		        this.z -= arguments[0].z;
  	        };
        };
        this.mult = function(){
          if( typeof arguments[0] == 'number' ){
  			    this.x *= arguments[0];
  			    this.y *= arguments[0];
  			    this.z *= arguments[0];
    		  }else if( typeof arguments[0] == 'object' ){
  			    this.x *= arguments[0].x;
  			    this.y *= arguments[0].y;
  			    this.z *= arguments[0].z;
    		  };
        };
        this.div = function(){
          if( typeof arguments[0] == 'number' ){
  			    this.x /= arguments[0];
  			    this.y /= arguments[0];
  			    this.z /= arguments[0];
    		  }else if( typeof arguments[0] == 'object' ){
  			    this.x /= arguments[0].x;
  			    this.y /= arguments[0].y;
  			    this.z /= arguments[0].z;
  			  };
        };
        this.dist = function(){
          var v = new p.PVector();
  		    v = arguments[0];
  		    var dx = this.x - v.x;
  		    var dy = this.y - v.y;
  		    var dz = this.z - v.z;
  		    return Math.sqrt( dx*dx + dy*dy + dz*dz );	
        };
        this.dot = function dot(){
  	      var num;
  	      if( arguments.length == 3 ){
  		      num = this.x * arguments[0] + this.y * arguments[1] + this.z * arguments[2];
  	      }else if( arguments.length == 2 ){
  		      var v1 = new p.PVector();
  		      var v2 = new p.PVector();
  		      v1 = arguments[0];
  		      v2 = arguments[1];
  		      num = v1.dot(v2);
  	      }else if( arguments.length == 1 ){
  		      var v = new p.PVector();
  		      v = arguments[0];
  		      num = this.x * v.x + this.y * v.y + this.z * v.z;
  	      };
  	      return num;
        };
        this.cross = function cross(){
  	      var crossX, crossY, crossZ;
  	      var v = new p.PVector(); // Will implement at later date - aSydiK :: What do you mean? - F1LT3R
  	      v = arguments[0];
  	      crossX = this.y * v.z - v.y * this.z;
  	      crossY = this.z * v.x - v.z * this.x;
  	      crossZ = this.x * v.y - v.x * this.y;
  	      return p.PVector( crossX, crossY, crossZ );
        };
        this.normalize = function normalize(){
  	      var m = this.mag();
  	      console.log( m );
  	      if( m > 0 ){ this.div( m ) };
        };
        this.limit = function limit( high ){
  	      if( this.mag() > high ){
  		      this.normalize();
  		      this.mult( high );
  	      };
        };
        this.angleBetween = function(){
            PVectorAngle.call( this, arguments );
        };
        this.array = function array(){
  	      var vArray = new Array( 3 );
  	      vArray[0] = this.x;
  	      vArray[1] = this.y;
  	      vArray[2] = this.z;
  	      return vArray;
        };
      }
      // End of PVector operations
      
  
      
      ////////////////////////////////////////////////////////////////////////////
      // Style functions
      ////////////////////////////////////////////////////////////////////////////
      
      p.noStroke   = function noStroke()  { doStroke = false; };    
      p.noFill     = function noFill()    { doFill = false;   };
      p.smooth     = function smooth()    {};
      p.noSmooth   = function noSmooth()  {};        
      
      p.fill = function fill(){
        doFill = true;
        curContext.fillStyle = p.color.apply( this, arguments );    
      };
      
      p.stroke = function stroke(){
        doStroke = true;
        curContext.strokeStyle = p.color.apply( this, arguments );
      };
  
      p.strokeWeight = function strokeWeight( w ){
        curContext.lineWidth = w;
      };
  
         
          
      ////////////////////////////////////////////////////////////////////////////
      // Vector drawing functions
      ////////////////////////////////////////////////////////////////////////////    
  
      p.Point = function Point( x, y ){
        this.x = x;
        this.y = y;
        this.copy = function(){
          return new 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.beginShape = function beginShape( type ){
        curShape = type;
        curShapeCount = 0; 
        curvePoints = [];
      };
      
      p.endShape = function endShape( close ){
        
        if( curShapeCount != 0 ){
          
          if( close || doFill ){ curContext.lineTo( firstX, firstY ); }
          if( doFill          ){ curContext.fill();                   }          
          if( doStroke        ){ curContext.stroke();                 }
        
          curContext.closePath();
          curShapeCount = 0;
          pathOpen = false;
          
        }
  
        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 && curShape != p.POINTS ){
  
          pathOpen = true;
          curContext.beginPath();
          curContext.moveTo( x, y );
          firstX = x;
          firstY = y;
  
        }else{
  
          if( curShape == p.POINTS ){
  
            p.point( x, y );
  
          }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 && 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 && 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( x, y );
              curShapeCount = 1;
            
            }
  
            if( curShape == p.QUAD_STRIP ){
              
              firstX  = secondX;
              firstY  = secondY;
              secondX = prevX;
              secondY = prevY;
              
            }
          
          }else if( arguments.length == 4 ){
          
            if( curShapeCount > 1 ){
              
              curContext.moveTo( prevX, prevY );
              curContext.quadraticCurveTo( firstX, firstY, x, y );
              curShapeCount = 1;
            
            }
          
          }else if( arguments.length == 6 ){
            
            curContext.bezierCurveTo( x, y, x2, y2, x3, y3 );
  
          }
        }
  
        prevX = x;
        prevY = y;
        curShapeCount ++;
        
        if(   curShape == p.LINES && curShapeCount == 2       ||
            ( curShape == p.TRIANGLES ) && curShapeCount == 3 ||
            ( curShape == p.QUADS     ) && curShapeCount == 4 
          ){
            p.endShape( p.CLOSE );
          }
      
      };
  
      p.curveVertex = function( x, y, x2, y2 ){
        
        if( curvePoints.length < 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();      
        }
      
      };
  
      p.curveTightness = function( tightness ){ curTightness = tightness; };
  
      p.bezierVertex = p.vertex;    
      
      p.rectMode     = function rectMode( aRectMode ){ curRectMode = aRectMode; };
      p.imageMode   = function (){};    
      p.ellipseMode = function ellipseMode( aEllipseMode ) { curEllipseMode = aEllipseMode; };        
      
      p.arc = function arc( x, y, width, height, start, stop ){
  
        if( width <= 0 ){ return; }
  
        if( curEllipseMode == p.CORNER ){
         x += width / 2;
         y += height / 2;
        }
        
        curContext.moveTo( x, y );
        curContext.beginPath();   
        curContext.arc( x, y, curEllipseMode == p.CENTER_RADIUS ? width : width/2, start, stop, false );
  
        if( doStroke ){ curContext.stroke(); }
        curContext.lineTo( x, y );
  
        if( doFill ){ curContext.fill(); }
        curContext.closePath();
        
      };
      
      p.line = function line( x1, y1, x2, y2 ){
        curContext.lineCap = "round";
        curContext.beginPath();    
        curContext.moveTo( x1 || 0, y1 || 0 );
        curContext.lineTo( x2 || 0, y2 || 0 );      
        curContext.stroke();      
        curContext.closePath();
      };
  
      p.bezier = function bezier( x1, y1, x2, y2, x3, y3, x4, y4 ){
        curContext.lineCap = "butt";
        curContext.beginPath();    
        curContext.moveTo( x1, y1 );
        curContext.bezierCurveTo( x2, y2, x3, y3, x4, y4 );      
        curContext.stroke();      
        curContext.closePath();
      };
  
      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 ){
        curContext.lineCap = "square";
        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 ){
  
        if( !( width + height ) ){ return; }
  
        curContext.beginPath();
        
        var offsetStart = 0;
        var offsetEnd = 0;
  
        if( curRectMode == p.CORNERS ){
          width -= x;
          height -= y;
        }
        
        if( curRectMode == p.RADIUS ){
          width *= 2;
          height *= 2;
        }
        
        if( curRectMode == p.CENTER || curRectMode == p.RADIUS ){
          x -= width / 2;
          y -= height / 2;
        }
      
        curContext.rect(
          Math.round( x ) - offsetStart,
          Math.round( y ) - offsetStart,
          Math.round( width ) + offsetEnd,
          Math.round( height ) + offsetEnd
        );
          
        if( doFill     ){ curContext.fill();   }        
        if( doStroke   ){  curContext.stroke() };
        
        curContext.closePath();
        
      };
      
      p.ellipse = function ellipse( x, y, width, height ){
  
        x = x || 0;
        y = y || 0;
  
        if( width <= 0 && height <= 0 ){ return; }
  
        curContext.beginPath();
        
        if( curEllipseMode == p.RADIUS ){
          width *= 2;
          height *= 2;
        }     
        
        var offsetStart = 0;
        
        // Shortcut for drawing a circle
        if( width == height ){
        
          curContext.arc( x - offsetStart, y - offsetStart, width / 2, 0, p.TWO_PI, false );
        
        }else{
        
          var w = width/2,
              h = height/2,
              C = 0.5522847498307933;
          var c_x = C * w,
              c_y = C * h;
  
  //!      Do we still need this? I hope the Canvas arc() more capable by now?
          curContext.moveTo( x + w, y );
          curContext.bezierCurveTo( x+w    ,   y-c_y  ,   x+c_x  ,   y-h   ,   x    ,   y-h  );
          curContext.bezierCurveTo( x-c_x  ,   y-h    ,   x-w    ,   y-c_y ,   x-w  ,   y    );
          curContext.bezierCurveTo( x-w    ,   y+c_y  ,   x-c_x  ,   y+h, x,   y+h           );
          curContext.bezierCurveTo( x+c_x  ,   y+h    ,   x+w    ,   y+c_y ,   x+w  ,   y    );
        
        }
      
        if( doFill    ){ curContext.fill();   }
        if( doStroke  ){ curContext.stroke(); }
        
        curContext.closePath();
        
      };
  
  
  
      ////////////////////////////////////////////////////////////////////////////
      // Raster drawing functions
      ////////////////////////////////////////////////////////////////////////////
  
      p.save = function save( file ){};
  
      // Loads an image for display. Type is unused. Callback is fired on load.
      p.loadImage = function loadImage( file, type, callback ){
        
        var img = document.createElement( 'img' );
        img.src = file;
       
        img.onload = function(){
          
          var h = this.height,
              w = this.width;
          
          var canvas = document.createElement( "canvas" );
          canvas.width = w;
          canvas.height = h;
          var context = canvas.getContext( "2d" );
       
          context.drawImage( this, 0, 0 );
          this.data = buildImageObject( context.getImageData( 0, 0, w, h ) );
          this.data.img = img;
  
          callback?callback():0;
          
        }
        
        return img;
            
      };
      
      // Gets a single pixel or block of pixels from the current Canvas Context
      p.get = function get( x, y ){
        
        if( !arguments.length ){
          var c = p.createGraphics( p.width, p.height );
          c.image( curContext, 0, 0 );
          return c;
        }
  
        if( !getLoaded ){
          getLoaded = buildImageObject( curContext.getImageData( 0, 0, p.width, p.height ) );
        }
  
        return getLoaded.get( x, y );
        
      };
  
      // Creates a new Processing instance and passes it back for... processing
      p.createGraphics = function createGraphics( w, h ){
   
        var canvas = document.createElement( "canvas" );
        var ret = buildProcessing( canvas );
        ret.size( w, h );
        ret.canvas = canvas;
        return ret;
   
      };
  
      // Paints a pixel array into the canvas
      p.set = function set( x, y, obj ){
        
        if( obj && obj.img ){
          
          p.image( obj, x, y );
          
        }else{
        
          var oldFill = curContext.fillStyle,
              color   = obj;
              
          curContext.fillStyle = color;
          curContext.fillRect( Math.round( x ), Math.round( y ), 1, 1 );
          curContext.fillStyle = oldFill;
          
        }
        
      };
  
      // Gets a 1-Dimensional pixel array from Canvas
      p.loadPixels = function(){
        p.pixels = buildImageObject( curContext.getImageData(0, 0, p.width, p.height) ).pixels;
      };
  
      // Draws a 1-Dimensional pixel array to Canvas
      p.updatePixels = function() {
      
        var colors = /(\d+),(\d+),(\d+),(\d+)/,
            pixels = {};
            
        pixels.width   = p.width;
        pixels.height = p.height;
        pixels.data   = [];
  
        if( curContext.createImageData ){
          pixels = curContext.createImageData( p.width, p.height );
        }
  
        var data   = pixels.data,
            pos   = 0;
  
        for( var i = 0, l = p.pixels.length; i < l; i++ ){
  
          var c = ( p.pixels[i] || "rgba(0,0,0,1)" ).match( colors );
  
          data[ pos + 0 ] =   parseInt( c[ 1 ] );
          data[ pos + 1 ] =   parseInt( c[ 2 ] );
          data[ pos + 2 ] =   parseInt( c[ 3 ] );
          data[ pos + 3 ] = parseFloat( c[ 4 ] ) * 255;
  
          pos += 4;
          
        }
  
        curContext.putImageData( pixels, 0, 0 );
        
      };
  
      // Draw an image or a color to the background
      p.background = function background( img ) {
        
         if( arguments.length ){
          
          if( img.data && img.data.img ){
            curBackground = img.data;
          }else{
            curBackground = p.color.apply( this, arguments );
          }
          
        }
  
        if( curBackground.img ){
        
          p.image( img, 0, 0 );
          
        }else{
  
          var oldFill = curContext.fillStyle;
          curContext.fillStyle = curBackground + "";
          curContext.fillRect( 0, 0, p.width, p.height );
          curContext.fillStyle = oldFill;
  
        }
        
      };    
      
      p.AniSprite = function( prefix, frames ){
        this.images = [];
        this.pos = 0;
  
        for( var i = 0; i < frames; i++ ){
          this.images.push( prefix + p.nf( i, ( "" + frames ).length ) + ".gif" );
        }
  
        this.display = function( x, y ){
          p.image_old( this.images[ this.pos ], x, y );
  
          if( ++this.pos >= frames ){
            this.pos = 0;
          }
        };
  
        this.getWidth   = function(){ return getImage_old( this.images[ 0 ] ).width;  };
        this.getHeight  = function(){ return getImage_old( this.images[ 0 ] ).height; };
      };
  
      function buildImageObject( obj ){
   
        var pixels = obj.data;
        var data = p.createImage( obj.width, obj.height );
  
        if( data.__defineGetter__ && data.__lookupGetter__ && !data.__lookupGetter__( "pixels" ) ){
          
          var pixelsDone;
          
          data.__defineGetter__( "pixels", function(){
            
            if( pixelsDone ){
              return pixelsDone;
            }
            pixelsDone = [];
  
            for( var i = 0; i < pixels.length; i += 4 ){
              pixelsDone.push(
                p.color(
                  pixels[ i ],
                  pixels[ i + 1 ],
                  pixels[ i + 2 ],
                  pixels[ i + 3 ])
                );
            }
  
            return pixelsDone;
          
          });
          
        }else{
          
          data.pixels = [];
  
          for ( var i = 0; i < pixels.length; i += 4 ){
            data.pixels.push( p.color(
              pixels[ i ],
              pixels[ i + 1 ],
              pixels[ i + 2 ],
              pixels[ i + 3 ]
            ));
          }
        
        }
  
        return data;
      }
  
      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;
        
      };
  
      function getImage( img ){
        
        if( typeof img == "string" ){
          return document.getElementById( img );
        }
  
        if( img.img ){
        
          return img.img;
          
        }else if( img.getContext || img.canvas ){
  
          img.pixels = img.getContext( '2d' ).createImageData( img.width, img.height );
        }
  
        for( var i = 0, l = img.pixels.length; i < l; i++ ){
          
          var pos = i * 4;
          var c = ( img.pixels[ i ] || "rgba(0,0,0,1)" ).slice( 5, - 1 ).split( "," );
          
          img.data[ pos + 0 ] =   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( "canvas" );
        canvas.width = img.width;
        canvas.height = img.height;
        
        var context = canvas.getContext( "2d" );
        context.putImageData( img.pixels, 0, 0 );
  
        img.canvas = canvas;
  
        return img;
      }
  
      // Depreciating "getImage_old" from PJS - currently here to support AniSprite
      function getImage_old( img ){ 
        if( typeof img == "string" ){
          return document.getElementById( img );
        } 
        if( img.img || img.canvas ){
          return img.img || img.canvas;
        } 
        for( var i = 0, l = img.pixels.length; i < l; i++ ){        
          var pos = i * 4;
          var c = ( img.pixels[ i ] || "rgba(0,0,0,1)" ).slice( 5, - 1 ).split( "," );        
          img.data[ pos + 0 ] = 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( "canvas" );
        canvas.width = img.width;
        canvas.height = img.height;      
        var context = canvas.getContext( "2d" );
        context.putImageData( img, 0, 0 ); 
        img.canvas = canvas; 
        return canvas;
      }
      // Depreciating "getImage_old" from PJS - currently here to support AniSprite
      p.image_old=function image_old(img,x,y,w,h){
        x = x || 0;
        y = y || 0; 
        var obj = getImage( img ); 
        if( curTint >= 0 ){
          var oldAlpha = curContext.globalAlpha;
          curContext.globalAlpha = curTint / opacityRange;
        } 
        if( arguments.length == 3 ){
          curContext.drawImage( obj, x, y );
        }else{
          curContext.drawImage( obj, x, y, w, h );
        } 
        if( curTint >= 0 ){
          curContext.globalAlpha = oldAlpha;
        } 
        if( img._mask ){
          var oldComposite = curContext.globalCompositeOperation;
          curContext.globalCompositeOperation = "darker";
          p.image( img._mask, x, y );
          curContext.globalCompositeOperation = oldComposite;
        }      
      };
  
      // Draws an image to the Canvas
      p.image = function image( img, x, y, w, h ){
        
        if( img.data || img.canvas ){
  
          x = x || 0;
          y = y || 0;
  
          var obj = getImage( img.data || img.canvas );
  
          if( curTint >= 0 ){
            var oldAlpha = curContext.globalAlpha;
            curContext.globalAlpha = curTint / opacityRange;
          }
  
          if( arguments.length == 3 ){
            curContext.drawImage( obj, x, y );
          }else{
            curContext.drawImage( obj, x, y, w, h );
          }
  
          if( curTint >= 0 ){
            curContext.globalAlpha = oldAlpha;
          }
  
          if( img._mask ){
            var oldComposite = curContext.globalCompositeOperation;
            curContext.globalCompositeOperation = "darker";
            p.image( img._mask, x, y );
            curContext.globalCompositeOperation = oldComposite;
          }
        
        }
        
        if( typeof img == 'string' ){
          
        }
        
      };    
      
      // Clears a rectangle in the Canvas element or the whole Canvas
      p.clear = function clear ( x, y, width, height ) {    
        if( arguments.length == 0 ){
          curContext.clearRect( 0, 0, p.width, p.height );
        }else{
          curContext.clearRect( x, y, width, height );
        }
      }
  
      p.tint = function tint( rgb, a ){
        curTint = a;
      };
  
  
  
      ////////////////////////////////////////////////////////////////////////////
      // Font handling
      ////////////////////////////////////////////////////////////////////////////
      
      // Loads a font from an SVG or Canvas API
      p.loadFont = function loadFont( name ){
        
        if( name.indexOf( ".svg" ) == - 1 ){
  
          return {
            name: name,
            width: function( str ){
              if( curContext.mozMeasureText ){
                return curContext.mozMeasureText(
                  typeof str == "number" ?
                    String.fromCharCode( str ) :
                    str
                ) / curTextSize;
              }else{
                return 0;
              }
            }
          };
          
        }else{
          
          // If the font is a glyph, calculate by SVG table     
          var font = p.loadGlyphs( name );
  
          return {
            name          : name,
            glyph         : true,
            units_per_em  : font.units_per_em,
            horiz_adv_x   : 1 / font.units_per_em * font.horiz_adv_x,
            ascent        : font.ascent,
            descent       : font.descent,
            width         :
              function( str ){
                var width = 0;
                var len   = str.length;
                for( var i = 0; i < len; i++ ){                          
                  try{ width += parseFloat( p.glyphLook( p.glyphTable[ name ], str[ i ] ).horiz_adv_x ); }
                  catch( e ){ ; }
                }
                return width / p.glyphTable[ name ].units_per_em;
              }
          }
          
        }
      
      };
  
      // Sets a 'current font' for use
      p.textFont = function textFont( name, size ){
        curTextFont = name;
        p.textSize( size );
      };
  
      // Sets the font size
      p.textSize = function textSize( size ){
  //!   Was this meant to return textSize value if no arguments were passed?
        if( size ){
          curTextSize = size;
        }
      };
  
      p.textAlign = function textAlign(){};
  
      // A lookup table for characters that can not be referenced by Object 
      p.glyphLook = function glyphLook( font, chr ){
  
        try{
          switch( chr ){
            case "1"  : return font[ "one"          ]; break;
            case "2"  : return font[ "two"          ]; break;
            case "3"  : return font[ "three"        ]; break;
            case "4"  : return font[ "four"         ]; break;
            case "5"  : return font[ "five"         ]; break;
            case "6"  : return font[ "six"          ]; break;
            case "7"  : return font[ "seven"        ]; break;
            case "8"  : return font[ "eight"        ]; break;
            case "9"  : return font[ "nine"         ]; break;
            case "0"  : return font[ "zero"         ]; break;
            case " "  : return font[ "space"        ]; break;
            case "$"  : return font[ "dollar"       ]; break;
            case "!"  : return font[ "exclam"       ]; break;
            case '"'  : return font[ "quotedbl"     ]; break;
            case "#"  : return font[ "numbersign"   ]; break;
            case "%"  : return font[ "percent"      ]; break;
            case "&"  : return font[ "ampersand"    ]; break;
            case "'"  : return font[ "quotesingle"  ]; break;
            case "("  : return font[ "parenleft"    ]; break;
            case ")"  : return font[ "parenright"   ]; break;
            case "*"  : return font[ "asterisk"     ]; break;
            case "+"  : return font[ "plus"         ]; break;
            case ","  : return font[ "comma"        ]; break;
            case "-"  : return font[ "hyphen"       ]; break;
            case "."  : return font[ "period"       ]; break;
            case "/"  : return font[ "slash"        ]; break;
            case "_"  : return font[ "underscore"   ]; break;
            case ":"  : return font[ "colon"        ]; break;
            case ";"  : return font[ "semicolon"    ]; break;
            case "<"  : return font[ "less"         ]; break;
            case "="  : return font[ "equal"        ]; break;
            case ">"  : return font[ "greater"      ]; break;
            case "?"  : return font[ "question"     ]; break;
            case "@"  : return font[ "at"           ]; break;
            case "["  : return font[ "bracketleft"  ]; break;
            case "\\" : return font[ "backslash"    ]; break;
            case "]"  : return font[ "bracketright" ]; break;
            case "^"  : return font[ "asciicircum"  ]; break;
            case "`"  : return font[ "grave"        ]; break;
            case "{"  : return font[ "braceleft"    ]; break;
            case "|"  : return font[ "bar"          ]; break;
            case "}"  : return font[ "braceright"   ]; break;
            case "~"  : return font[ "asciitilde"   ]; break;
            // If the character is not 'special', access it by object reference
            default   : return font[ chr            ]; break;
          }
        }catch( e ){ ; }
      
      }
      
      // Print some text to the Canvas
      p.text = function text( str, x, y ){
        
        // If the font is a standard Canvas font...
        if( !curTextFont.glyph ){
        
          if( str && curContext.mozDrawText ){
  
            curContext.save();
            curContext.mozTextStyle = curTextSize + "px " + curTextFont.name;
            curContext.translate( x, y );
            curContext.mozDrawText( 
              typeof str == "number" ?
              String.fromCharCode( str ) :
              str ) ;
            curContext.restore();
  
          }
          
        }else{
          
          // If the font is a Batik SVG font...
          var font = p.glyphTable[ curTextFont.name ];
          curContext.save();
          curContext.translate( x, y + curTextSize );
          
          var upem      = font[ "units_per_em" ],
              newScale = 1 / upem * curTextSize;
          
          curContext.scale( newScale, newScale );
          
          var len = str.length;
          
          for(var i = 0; i < len; i++ ){
            // Test character against glyph table
            try{ p.glyphLook( font, str[ i ] ).draw(); }
            catch( e ){ ; }
          }
          
          curContext.restore();
        }
        
      };
      
      // Load Batik SVG Fonts and parse to pre-def objects for quick rendering 
      p.loadGlyphs = function loadGlyph( url ){
          
          // Load and parse Batik SVG font as XML into a Processing Glyph object
          var loadXML = function loadXML(){
          
            try{
                        var xmlDoc = new ActiveXObject( "Microsoft.XMLDOM" );
            }
            catch( e ){ 
                        try{
                              xmlDoc=document.implementation.createDocument( "", "", null );
                        }
                        catch( e ){
                              p.println( e.message );
                              return;
                        }
            };
            
            try{
                        xmlDoc.async = false;
                        xmlDoc.load( url );
                        parse( xmlDoc.getElementsByTagName( "svg" )[ 0 ] );
            }
            catch( e ){
                        // Google Chrome, Safari etc.
                        try{
                              p.println( e.message );
                              var xmlhttp = new window.XMLHttpRequest();
                              xmlhttp.open( "GET", url, false );
                              xmlhttp.send( null );
                              parse( xmlhttp.responseXML.documentElement );
                        }
                        catch( e ){ ; }
            }
          };
          
          // Return arrays of SVG commands and coords
          var regex = function regex( needle, hay ){
            
            var regexp  = new RegExp( needle, "g" ),
                results = [],
                i       = 0;
                
            while( results[ i ] = regexp.exec( hay ) ){ i++; }
            return results;
          
          }
  
          // Parse SVG font-file into block of Canvas commands
          var parse = function parse( svg ){
            
            // Store font attributes
            var font = svg.getElementsByTagName( "font" );
            p.glyphTable[ url ][ "horiz_adv_x"  ] = font[ 0 ].getAttribute( "horiz-adv-x" );      
            
            var font_face = svg.getElementsByTagName( "font-face" )[ 0 ];                  
            p.glyphTable[ url ][ "units_per_em" ] = parseFloat( font_face.getAttribute( "units-per-em") );
            p.glyphTable[ url ][ "ascent"       ] = parseFloat( font_face.getAttribute( "ascent"      ) );
            p.glyphTable[ url ][ "descent"      ] = parseFloat( font_face.getAttribute( "descent"     ) );          
            
            var getXY = "[0-9\-]+",
                glyph = svg.getElementsByTagName( "glyph" ),
                len   = glyph.length;
  
            // Loop through each glyph in the SVG
            for( var i = 0; i < len; i++ ){
              
              // Store attributes for this glyph
              var unicode = glyph[ i ].getAttribute( "unicode" );
              var name = glyph[ i ].getAttribute( "glyph-name" );
              var horiz_adv_x = glyph[ i ].getAttribute( "horiz-adv-x" );
              if( horiz_adv_x == null ){ var horiz_adv_x = p.glyphTable[ url ][ 'horiz_adv_x' ]; }
              
              var buildPath = function buildPath( d ){ 
                
                var c = regex( "[A-Za-z][0-9\- ]+|Z", d );                                                    
                
                // Begin storing path object 
                var path = "var path={draw:function(){curContext.beginPath();curContext.save();";
                
                var x       = 0,
                    y       = 0,
                    cx      = 0,
                    cy      = 0,
                    nx      = 0,
                    ny      = 0,
                    d       = 0,
                    a       = 0,
                    lastCom = "",
                    lenC    = c.length - 1;
                
                // Loop through SVG commands translating to canvas eqivs functions in path object
                for( var j = 0; j < lenC; j++ ){
                  
                  var com = c[ j ][ 0 ],
                      xy   = regex( getXY, com );
         
                  switch( com[ 0 ] ){
                  
                    case "M": //curContext.moveTo(x,-y);
                      x = parseFloat( xy[ 0 ][ 0 ] );
                      y = parseFloat( xy[ 1 ][ 0 ] );              
  //!                 Brackets needed on (-y)?
                      path += "curContext.moveTo("+ x +","+ (-y) +");";
                      break;
  
                    case "L": //curContext.lineTo(x,-y);
                      x = parseFloat( xy[ 0 ][ 0 ] );
                      y = parseFloat( xy[ 1 ][ 0 ] );
                      path += "curContext.lineTo("+ x +","+ (-y) +");";
                      break;
  
                    case "H"://curContext.lineTo(x,-y)
                      x = parseFloat( xy[ 0 ][ 0 ] );
                      path += "curContext.lineTo("+ x +","+ (-y) +");";
                      break;
  
                    case "V"://curContext.lineTo(x,-y);
                      y = parseFloat( xy[ 0 ][ 0 ] );              
                      path += "curContext.lineTo("+ x +","+ (-y) +");";
                      break;
  
                    case "T"://curContext.quadraticCurveTo(cx,-cy,nx,-ny);
                      nx = parseFloat( xy[ 0 ][ 0 ] );
                      ny = parseFloat( xy[ 1 ][ 0 ] );
  
                      if( lastCom == "Q" || lastCom == "T" ){
  
                        d = Math.sqrt( Math.pow( x - cx, 2 ) + Math.pow( cy - y, 2 ) );
                        a = Math.PI+Math.atan2( cx - x, cy - y );
                        cx = x + ( Math.sin( a ) * ( d ) );
                        cy = y + ( Math.cos( a ) * ( d ) );
  
                      }else{
                        cx = x;
                        cy = y;
                      }
                      
                      path += "curContext.quadraticCurveTo("+ cx +","+ (-cy) +","+ nx +","+ (-ny) +");";
                      x = nx;
                      y = ny;
                      break;
                       
                    case "Q"://curContext.quadraticCurveTo(cx,-cy,nx,-ny);
                      cx = parseFloat( xy[ 0 ][ 0 ] );
                      cy = parseFloat( xy[ 1 ][ 0 ] );
                      nx = parseFloat( xy[ 2 ][ 0 ] );
                      ny = parseFloat( xy[ 3 ][ 0 ] ); 
                      path += "curContext.quadraticCurveTo("+ cx +","+ (-cy) +","+ nx +","+ (-ny) +");";              
                      x = nx;
                      y = ny;
                      break;
  
                    case "Z"://curContext.closePath();
                      path += "curContext.closePath();";
                      break;
  
                  }
  
                  lastCom = com[ 0 ];
  
                }
  
                path += "doStroke?curContext.stroke():0;";
                path += "doFill?curContext.fill():0;";
                path += "curContext.restore();";
                path += "curContext.translate("+ horiz_adv_x  +",0);";            
                path += "}}";
  
                return path;
  
              }
                       
              var d = glyph[ i ].getAttribute( "d" );
              
              // Split path commands in glpyh 
              if( d !== undefined ){
              
                var path = buildPath( d );
                eval( path );
                
                // Store glyph data to table object
                p.glyphTable[ url ][ name ] = {
                  name        : name,
                  unicode     : unicode,
                  horiz_adv_x : horiz_adv_x,
                  draw        : path.draw
                }
  
              }
           
            } // finished adding glyphs to table
            
          }
          
          // Create a new object in glyphTable to store this font
          p.glyphTable[ url ] = {};
          
          // Begin loading the Batik SVG font... 
          loadXML( url );
          
          // Return the loaded font for attribute grabbing
          return p.glyphTable[ url ];
      }
  
  
  
      ////////////////////////////////////////////////////////////////////////////
      // Class methods
      ////////////////////////////////////////////////////////////////////////////
      
      p.extendClass = function extendClass( obj, args, fn ){
        if( arguments.length == 3 ){
          fn.apply( obj, args );
        }else{
          args.call( obj );
        }
      };
  
      p.addMethod = function addMethod( object, name, fn ){
  
        if( object[ name ] ){
        
          var args   = fn.length,
              oldfn = object[ name ];
          
          object[ name ] = function(){
            
            if( arguments.length == args ){
  
              return fn.apply( this, arguments );
  
            }else{
  
              return oldfn.apply( this, arguments );
  
            }
          
          };
        
        }else{
        
          object[ name ] = fn;
        
        }
      
      };
      
      
  
      ////////////////////////////////////////////////////////////////////////////
      // Set up environment
      ////////////////////////////////////////////////////////////////////////////
      
      p.init = function init(code){
  
        p.stroke( 0 );
        p.fill( 255 );
      
        // Canvas has trouble rendering single pixel stuff on whole-pixel
        // counts, so we slightly offset it (this is super lame).
        
        curContext.translate( 0.5, 0.5 );    
            
        // The fun bit!
        if( code ){
          (function( Processing ){
            with ( p ){
              eval(parse(code, p));
            }
          })( p );
        }
      
        if( p.setup ){
          inSetup = true;
          p.setup();
        }
        
        inSetup = false;
        
        if( p.draw ){
          if( !doLoop ){
            p.redraw();
          } else {
            p.loop();
          }
        }
        
  
        //////////////////////////////////////////////////////////////////////////
        // Event handling
        //////////////////////////////////////////////////////////////////////////
        
        attach( curElement, "mousemove"  , 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 + scrollX;
          p.mouseY   = e.clientY - curElement.offsetTop + scrollY;    
  
          if( p.mouseMoved ){ p.mouseMoved(); }
          if( mousePressed && p.mouseDragged ){ p.mouseDragged(); }
          
        });
        
        attach( curElement, "mouseout" , function( e ){ p.cursor("auto"); });      
        
        attach( curElement, "mousedown", function( e ){      
          mousePressed = true;      
          switch(e.which){
            case 1: p.mouseButton = p.LEFT; break;
            case 2: p.mouseButton = p.CENTER; break;
            case 3: p.mouseButton = p.RIGHT; break; 
          }        
          p.mouseDown = true;        
          if( typeof p.mousePressed == "function" ){ p.mousePressed(); }
          else{ p.mousePressed = true; }
        });
  
        attach( curElement, "mouseup", function( e ){
          mousePressed = false;
          if( p.mouseClicked ){ p.mouseClicked(); }        
          if( typeof p.mousePressed != "function" ){ p.mousePressed = false; }
          if( p.mouseReleased ){ p.mouseReleased(); }
        });
  
        attach( document, "keydown", function( e ){
          keyPressed = true;
          p.key = e.keyCode + 32;               
          var i, len = p.codedKeys.length;        
          for( i=0; i < len; i++ ){
              if( p.key == p.codedKeys[ i ] ){
                switch(p.key){
                case 70: p.keyCode = p.UP        ; break;
                case 71: p.keyCode = p.RIGHT    ; break;
                case 72: p.keyCode = p.DOWN      ; break;
                case 69: p.keyCode = p.LEFT      ; break;
                }
                p.key=p.CODED;
              }
          }
          if( e.shiftKey ){ p.key = String.fromCharCode(p.key).toUpperCase().charCodeAt( 0 ); }
          if( typeof p.keyPressed == "function" ){ p.keyPressed(); }
          else{ p.keyPressed = true; }
        });
  
        attach( document, "keyup", function( e ){
          keyPressed = false;
          if( typeof p.keyPressed != "function" ){ p.keyPressed = false; }
          if( p.keyReleased ){ p.keyReleased(); }
        });
  
        function attach(elem, type, fn) {
          if( elem.addEventListener ){ elem.addEventListener( type, fn, false ); }
          else{ elem.attachEvent( "on" + type, fn ); }
        }
  
      };
  
      return p;
      
    }
  
  })();
  