
var Curly={};Curly.extend=function(targetObj,sourceObj){for(var i=1;i<arguments.length;i++){for(var k in arguments[i]){targetObj[k]=arguments[i][k];}}
return targetObj;};Curly.extendClass=function(child,parent,methods){parent.prototype.constructor=parent;var extendHelper=function(){};extendHelper.prototype=parent.prototype;child.prototype=new extendHelper();Curly.extend(child.prototype,parent.prototype);if(methods!==undefined){Curly.extend(child.prototype,methods);}
child.superclass=parent.prototype;return child;};Curly.cloneArray=function(ar){var clone=[];for(var i=0;i<ar.length;i++){if(ar[i]instanceof Array){clone.push(ar[i].clone());}
else{clone.push(ar[i]);}}
return clone;};Curly.Canvas=function(source){Curly.Canvas.superclass.constructor.call(this);var self=this;var ctx=null;var stateStack=[];this.getCtx=function(){return ctx;};if(typeof source=='string'){source=document.getElementById(source);if(!source){throw new Curly.Canvas.Error('The given argument is no valid element id');}}
if(window.CanvasRenderingContext2D&&source instanceof CanvasRenderingContext2D){ctx=source;}
else if(source.tagName.toLowerCase()=='canvas'){if(window.G_vmlCanvasManager){G_vmlCanvasManager.initElement(source);}
ctx=source.getContext('2d');}
else{throw new Curly.Canvas.Error('The given argument is no valid parameter');}
this.xCorrection=0.5;this.yCorrection=0.5;this.useCorrection=true;this.useIntCorrection=false;var determineStyle=function(o){if(o instanceof Curly.Gradient){return o.createGradient(ctx,this);}
else{return o;}};var setState=function(){var s;if(stateStack.length<=0){s=Curly.Canvas.State.DEFAULTS;stateStack.push(s);}
else{s=stateStack[stateStack.length-1];}
var t=s.transform;if(!(t instanceof Array)||t.length<6){t=Curly.Canvas.State.IDENTITY_MATRIX;}
ctx.setTransform(t[0],t[1],t[2],t[3],t[4],t[5]);ctx.scale(s.scaleX,s.scaleY);ctx.rotate(s.rotate);var tx=s.translateX,ty=s.translateY;if(self.useCorrection){if(self.useIntCorrection){tx+=parseInt(self.xCorrection);ty+=parseInt(self.yCorrection);}
else{tx+=self.xCorrection;ty+=self.yCorrection;}}
ctx.translate(tx,ty);ctx.globalAlpha=s.alpha;ctx.globalCompositeOperation=s.compositeOperation;ctx.lineWidth=s.lineWidth;ctx.lineCap=s.lineCap;ctx.lineJoin=s.lineJoin;ctx.miterLimit=s.miterLimit;ctx.shadowOffsetX=s.shadowOffsetX;ctx.shadowOffsetY=s.shadowOffsetY;ctx.shadowBlur=s.shadowBlur;ctx.shadowColor=s.shadowColor;ctx.strokeStyle=determineStyle(s.strokeStyle);ctx.fillStyle=determineStyle(s.fillStyle);ctx.font=s.font;ctx.textAlign=s.textAlign;ctx.textBaseline=s.textBaseline;};this.getElement=function(){return ctx.canvas;};this.getWidth=function(){return ctx.canvas.width;};this.setWidth=function(v){return this.setDimensions([v,this.getHeight()]);};this.getHeight=function(){return ctx.canvas.height;};this.setHeight=function(v){return this.setDimensions([this.getWidth(),v]);};this.getDimensions=function(){return[this.getWidth(),this.getHeight()];};this.setDimensions=function(dim){var w=dim[0],h=dim[1];var data=null;if(ctx.getImageData){data=ctx.getImageData(0,0,Math.min(this.getWidth(),w),Math.min(this.getHeight(),h));}
ctx.canvas.width=w;ctx.canvas.height=h;if(data){ctx.putImageData(data,0,0);}
return this;};this.getState=function(){if(stateStack.length<=0){return undefined;}
else{return stateStack[stateStack.length-1];}};this.pushState=function(state){stateStack.push(state);return this;};this.popState=function(n){var state;for(var i=0,n=n||1;i<n;i++){state=stateStack.pop();}
return state;};this.pushDefaultState=function(){return this.pushState(new Curly.Canvas.State());};this.applyState=function(){setState();return this;};this.overwriteState=function(changes){if(typeof changes=='string'){var tmp={};tmp[changes]=arguments[1];changes=tmp;}
var state={};var currentState=this.getState();if(currentState!=undefined){Curly.extend(state,currentState);}
this.pushState(new Curly.Canvas.State(Curly.extend(state,changes)));return this;};this.getImageData=function(x,y,w,h){if(x===undefined){x=0;}
if(y===undefined){y=0;}
if(w===undefined){w=this.getWidth();}
if(h===undefined){h=this.getHeight();}
return ctx.getImageData(x,y,w,h);};var drawImage=function(el,srcX,srcY,srcW,srcH,dstX,dstY,dstW,dstH){var tmp=this.useIntCorrection;this.useIntCorrection=true;this.applyState();ctx.drawImage(el,srcX,srcY,srcW,srcH,dstX,dstY,dstW,dstH);this.useIntCorrection=tmp;this.applyState();};this.copy=function(data,dstX,dstY,srcX,srcY,srcW,srcH){if(srcX===undefined){srcX=0;}
if(srcY===undefined){srcY=0;}
if(dstX===undefined){dstX=0;}
if(dstY===undefined){dstY=0;}
var isCanvas=(data instanceof Curly.Canvas);var isContext=(data instanceof CanvasRenderingContext2D);if(isCanvas||isContext||data instanceof Element){var elW,elH;if(isCanvas){el=data.getElement();}
else if(isContext){el=data.canvas;}
else{el=data;elW=el.offsetWidth;elH=el.offsetHeight;}
if(srcW===undefined){srcW=elW?elW:el.width;}
if(srcH===undefined){srcH=elH?elH:el.height;}
drawImage.call(this,el,srcX,srcY,srcW,srcH,dstX,dstY,srcW,srcH);}
else{if(data.width>this.getWidth()+dstX){throw new Curly.Canvas.Error('The width attribute of the given ImageData is too big');}
else if(data.height>this.getHeight()+dstY){throw new Curly.Canvas.Error('The width attribute of the given ImageData is too big');}
ctx.putImageData(data,dstX,dstY);}
return this;};this.copyResized=function(data,dstX,dstY,srcX,srcY,dstW,dstH,srcW,srcH){if(srcX===undefined){srcX=0;}
if(srcY===undefined){srcY=0;}
if(dstX===undefined){dstX=0;}
if(dstY===undefined){dstY=0;}
if(dstW===undefined){dstW=this.getWidth();}
if(dstH===undefined){dstH=this.getHeight();}
if(data instanceof Curly.Canvas){el=data.getElement();}
else{el=data.canvas;}
if(srcW===undefined){srcW=el.width;}
if(srcH===undefined){srcH=el.height;}
drawImage.call(this,el,srcX,srcY,srcW,srcH,dstX,dstY,dstW,dstH);return this;};this.clear=function(){var tmp=this.useCorrection;this.useCorrection=false;setState();ctx.clearRect(0,0,this.getWidth(),this.getHeight());this.useCorrection=tmp;return this;};this.path=function(x,y){var p=new Curly.Path(x,y);p.canvas=this;return p;};this.statefulPath=function(x,y){var p=new Curly.StatefulPath(x,y);p.canvas=this;return p;};this.draw=function(drawable){if(!(drawable instanceof Curly.Drawable)){throw new Curly.Canvas.Error('The given object is no drawable object');}
setState();drawable.draw(ctx,this);return this;};this.clip=function(shape){if(!(shape instanceof Curly.Shape)){throw new Curly.Canvas.Error('The given object is no shape object');}
ctx.restore();ctx.save();var tmp=this.useCorrection;this.useCorrection=false;setState();if(!(shape instanceof Curly.Path)){shape=shape.getPath(this);}
shape.draw(false,false);ctx.clip();this.useCorrection=tmp;setState();return this;};this.unclip=function(){return this.clip(new Curly.Rectangle(0,0,this.getWidth(),this.getHeight()));};this.pushDefaultState();};Curly.extendClass(Curly.Canvas,Object);Curly.Canvas.Error=function(msg){this.msg=msg;this.toString=function(){return this.msg;};};Curly.Canvas.State=function(config){Curly.extend(this,Curly.Canvas.State.DEFAULTS,config||{});};Curly.Canvas.State.IDENTITY_MATRIX=[1,0,0,1,0,0];Curly.Canvas.State.OP_SOURCE_OVER='source-over';Curly.Canvas.State.OP_SOURCE_IN='source-in';Curly.Canvas.State.OP_SOURCE_OUT='source-out';Curly.Canvas.State.OP_SOURCE_atop='source-atop';Curly.Canvas.State.OP_DESTINATION_OVER='destination-over';Curly.Canvas.State.OP_DESTINATION_IN='destination-in';Curly.Canvas.State.OP_DESTINATION_OUT='destination-out';Curly.Canvas.State.OP_DESTINATION_atop='destination-atop';Curly.Canvas.State.OP_LIGHTER='lighter';Curly.Canvas.State.OP_COPY='copy';Curly.Canvas.State.OP_XOR='xor';Curly.Canvas.State.CAP_BUTT='butt';Curly.Canvas.State.CAP_ROUND='round';Curly.Canvas.State.CAP_SQUARE='square';Curly.Canvas.State.JOIN_ROUND='round';Curly.Canvas.State.JOIN_BEVEL='bevel';Curly.Canvas.State.JOIN_MITER='miter';Curly.Canvas.State.ALIGN_START='start';Curly.Canvas.State.ALIGN_END='end';Curly.Canvas.State.ALIGN_LEFT='left';Curly.Canvas.State.ALIGN_RIGHT='right';Curly.Canvas.State.ALIGN_CENTER='center';Curly.Canvas.State.BASELINE_TOP='top';Curly.Canvas.State.BASELINE_HANGING='hanging';Curly.Canvas.State.BASELINE_MIDDLE='middle';Curly.Canvas.State.BASELINE_ALPHABETIC='alphabetic';Curly.Canvas.State.BASELINE_IDEOGRAPHIC='ideographic';Curly.Canvas.State.BASELINE_BOTTOM='bottom';Curly.Canvas.State.DEFAULTS={scaleX:1.0,scaleY:1.0,rotate:0,translateX:0,translateY:0,transform:null,compositeOperation:Curly.Canvas.State.OP_SOURCE_OVER,lineWidth:1.0,lineCap:Curly.Canvas.State.CAP_BUTT,lineJoin:Curly.Canvas.State.JOIN_ROUND,miterLimit:10,alpha:1.0,strokeStyle:'black',fillStyle:'black',shadowOffsetX:0.0,shadowOffsetY:0.0,shadowBlur:0.0,shadowColor:'black',font:'10px sans-serif',textAlign:Curly.Canvas.State.ALIGN_START,textBaseline:Curly.Canvas.State.BASELINE_ALPHABETIC};Curly.Canvas.State.COLOR_TRANSPARENT='rgba(0,0,0,0)';Curly.Transparent='rgba(0,0,0,0)';Curly.Drawable=function(x,y){this.x=x||0;this.y=y||0;};Curly.extendClass(Curly.Drawable,Object,{drawFill:true,drawStroke:true,getXY:function(){return[this.x,this.x];},moveTo:function(x,y){this.x=x;this.y=y;return this;},draw:function(context,canvas){}});Curly.Shape=function(x,y){Curly.Shape.superclass.constructor.call(this,x,y);};Curly.extendClass(Curly.Shape,Curly.Drawable,{getPath:function(canvas){},draw:function(context,canvas){var path=this.getPath(canvas);path.drawFill=this.drawFill;path.drawStroke=this.drawStroke;canvas.draw(path);}});Curly.Path=function(x,y){Curly.Path.superclass.constructor.call(this,x,y);this.comp=[['beginPath']];this.pushPosition();};Curly.extendClass(Curly.Path,Curly.Shape,{canvas:null,lastX:-1,lastY:-1,comp:null,close:function(){this.comp.push(['closePath']);return this;},pushPosition:function(forceSave){if(this.lastX!=this.x||this.lastY!=this.y||forceSave){this.comp.push(['moveTo',this.x,this.y]);this.lastX=this.x;this.lastY=this.y;}
return this;},moveTo:function(x,y){Curly.Path.superclass.moveTo.call(this,x,y);this.pushPosition();return this;},setPosition:function(x,y){Curly.Path.superclass.moveTo.call(this,x,y);return this;},lineTo:function(x,y){this.comp.push(['lineTo',x,y]);this.setPosition(x,y);return this;},rect:function(w,h){this.pushPosition();this.comp.push(['rect',this.x,this.y,w,h]);return this;},arcTo:function(x1,y1,r){this.pushPosition();this.comp.push(['arcTo',this.x,this.y,x1,y1,r]);this.moveTo(x1,y1);return this;},arc:function(r,sa,se,acw){this.pushPosition();this.comp.push(['moveTo',this.x+r,this.y]);this.comp.push(['arc',this.x,this.y,r,sa||0,se||Math.PI<<1,acw||false]);this.moveTo(this.x+r,this.y);return this;},dot:function(){this.pushPosition();this.comp.push(['fillRect',this.x+0.5,this.y+0.5,1,1]);return this;},quadCurve:function(cpx,cpy,x,y){this.pushPosition();this.comp.push(['quadraticCurveTo',cpx,cpy,x,y]);this.moveTo(x,y);return this;},bezier:function(cp1x,cp1y,cp2x,cp2y,x,y){this.pushPosition();this.comp.push(['bezierCurveTo',cp1x,cp1y,cp2x,cp2y,x,y]);this.moveTo(x,y);return this;},getPath:function(canvas){if(canvas===this.canvas){return this;}
var clone=new this.constructor();clone.canvas=canvas;clone.comp=Curly.cloneArray(this.comp);return clone;},draw:function(context,canvas){if(!(canvas instanceof Curly.Canvas)){this.drawFill=!(context===false);this.drawStroke=!(canvas===false);if(this.canvas instanceof Curly.Canvas){canvas=this.canvas;context=canvas.getCtx();}
else{throw new Curly.Canvas.Error('No canvas given');}}
canvas.applyState();context.beginPath();for(var i=0;i<this.comp.length;i++){var a=[].concat(this.comp[i]);var method=a.shift();context[method].apply(context,a);}
if(this.drawFill){context.fill();}
if(this.drawStroke){context.stroke();}
return this;}});Curly.StatefulPath=function(x,y,canvas){Curly.StatefulPath.superclass.constructor.apply(this,arguments);};Curly.extendClass(Curly.StatefulPath,Curly.Path,{add:function(drawable){this.comp.push(drawable);return this;},setState:function(state,value){if(typeof state==='string'){var tmp={};tmp[state]=value;state=tmp;}
this.comp.push(['overwriteState',state]);this.comp.push(['applyState']);this.pushPosition(true);return this;},draw:function(context,canvas){if(!(canvas instanceof Curly.Canvas)){this.drawFill=!(context===false);this.drawStroke=!(canvas===false);if(this.canvas instanceof Curly.Canvas){canvas=this.canvas;context=canvas.getCtx();}
else{throw new Curly.Canvas.Error('No canvas given');}}
var self=this;var render=function(){if(self.drawFill){context.fill();}
if(self.drawStroke){context.stroke();}};context.beginPath();var comp;for(var i in this.comp){comp=this.comp[i];var a=[].concat(comp);var method=a.shift();if(method instanceof Curly.Drawable){render();context.closePath();canvas.draw(method);context.beginPath();}
else if(!context[method]){if(!canvas[method]){throw new Curly.Canvas.Error('Method '+method+' not found');}
render();context.closePath();canvas[method].apply(canvas,a);context.beginPath();}
else{context[method].apply(context,a);}}
render();context.closePath();return this;}});Curly.Rectangle=function(x,y,w,h){Curly.Rectangle.superclass.constructor.call(this,x,y);this.w=w||0;this.h=h||0;this.resize=function(w,h){this.w=w;this.h=h;return this;};this.getPath=function(canvas){return canvas.path(this.x,this.y).rect(this.w,this.h);};};Curly.extendClass(Curly.Rectangle,Curly.Shape);Curly.Pixel=function(x,y){Curly.Pixel.superclass.constructor.call(this,x,y);this.getPath=function(canvas){return canvas.path(this.x,this.y).dot();};};Curly.extendClass(Curly.Pixel,Curly.Shape);Curly.Bezier=function(x0,y0,x1,y1,cp1x,cp1y,cp2x,cp2y){Curly.Bezier.superclass.constructor.call(this,x0,y0);this.x1=x1||0;this.y1=y1||0;this.cp1x=cp1x||0;this.cp1y=cp1y||0;this.cp2x=cp2x||0;this.cp2y=cp2y||0;this.getPath=function(canvas){return canvas.path(this.x,this.y).bezier(this.cp1x,this.cp1y,this.cp2x,this.cp2y,this.x1,this.y1);};};Curly.extendClass(Curly.Bezier,Curly.Shape);Curly.BezierLine=function(x0,y0,x1,y1,cp1x,cp1y,cp2x,cp2y){Curly.BezierLine.superclass.constructor.apply(this,arguments);this.drawFill=false;};Curly.extendClass(Curly.BezierLine,Curly.Bezier);Curly.QuadCurve=function(x0,y0,x1,y1,cpx,cpy){Curly.QuadCurve.superclass.constructor.call(this,x0,y0);this.x1=x1||0;this.y1=y1||0;this.cpx=cpx||0;this.cpy=cpy||0;this.getPath=function(canvas){return canvas.path().moveTo(this.x,this.y).quadCurve(this.cpx,this.cpy,this.x1,this.y1);};};Curly.extendClass(Curly.QuadCurve,Curly.Shape);Curly.Arc=function(x,y,r,sa,ea,acw){Curly.Arc.superclass.constructor.call(this,x,y);this.radius=r||0;this.startAngle=sa||0;this.endAngle=ea===undefined?Math.PI*2:ea;this.antiClockwise=!!acw;this.getPath=function(canvas){return canvas.path(this.x,this.y).arc(this.radius,this.startAngle,this.endAngle,this.antiClockwise);};};Curly.extendClass(Curly.Arc,Curly.Shape);Curly.ArcLine=function(x,y,r,sa,ea,acw){Curly.ArcLine.superclass.constructor.apply(this,arguments);this.drawFill=false;};Curly.extendClass(Curly.ArcLine,Curly.Arc);Curly.Gradient=function(stops){this.stops=[];if(stops instanceof Array){for(var i=0,n=stops.length;i<n;i++){this.addColorStop(stops[i][0],stops[i][1]);}}
else if(typeof stops==='object'){this.addColorStop(stops[0],stops[1]);}};Curly.Gradient.prototype.addColorStop=function(offset,color){this.stops.push([offset,color]);return this;};Curly.Gradient.prototype.createGradient=function(context,canvas){throw new Curly.Canvas.Error('Not implemented');};Curly.Gradient.prototype.applyColorStops=function(gradient){for(var i=0,n=this.stops.length;i<n;i++){gradient.addColorStop(this.stops[i][0],this.stops[i][1]);}};Curly.Gradient.Linear=function(stops){if(typeof stops==='object'){Curly.extend(this,stops);stops=stops.stops;}
Curly.Gradient.Linear.superclass.constructor.call(this,stops);};Curly.extendClass(Curly.Gradient.Linear,Curly.Gradient,{x0:0,y0:0,x1:100,y1:100,positionLine:function(length,angle){this.x1=length*Math.sin(angle)+this.x0;this.y1=length*Math.cos(angle)+this.y0;},createGradient:function(context,canvas){var gr=context.createLinearGradient(this.x0,this.y0,this.x1,this.y1);this.applyColorStops(gr);return gr;}});Curly.Gradient.Radial=function(stops){if(typeof stops==='object'){if(stops.x){stops.x0=stops.x1=stops.x;delete stops.x;}
if(stops.y){stops.y0=stops.y1=stops.y;delete stops.y;}
if(stops.r){stops.r1=stops.r;delete stops.r;}
Curly.extend(this,stops);stops=stops.stops;}
Curly.Gradient.Radial.superclass.constructor.call(this,stops);};Curly.extendClass(Curly.Gradient.Radial,Curly.Gradient,{x0:0,y0:0,r0:0,x1:0,y1:0,r1:100,createGradient:function(context,canvas){var gr=context.createRadialGradient(this.x0,this.y0,this.r0,this.x1,this.y1,this.r1);this.applyColorStops(gr);return gr;}});Curly.Smiley=function(x,y,config){Curly.Smiley.superclass.constructor.apply(this,arguments);Curly.extend(this,config);};Curly.extendClass(Curly.Smiley,Curly.Shape,{mainColor:'yellow',borderColor:'black',getPath:function(canvas){return canvas.statefulPath().setState({lineWidth:1,fillStyle:this.mainColor,strokeStyle:this.borderColor}).add(new Curly.Arc(150,75,50)).setState('fillStyle','black').add(new Curly.Arc(130,60,10)).add(new Curly.Arc(170,60,10)).setState({fillStyle:Curly.Transparent,strokeStyle:'red',lineWidth:2}).add(new Curly.Bezier(120,90,180,90,130,115,170,115)).setState({lineWidth:1});}});Curly.Text=function(x,y,text,font){this.text=text+""||'';this.font=font+""||Curly.Canvas.State.DEFAULTS.font;this.drawStroke=false;Curly.Text.superclass.constructor.call(this,x,y);};Curly.extendClass(Curly.Text,Curly.Drawable,{maxWidth:undefined,draw:function(context,canvas){canvas.applyState();var args=[this.text,this.x,this.y];if(this.maxWidth!==undefined){args.push(this.maxWidth);}
if(this.drawFill){context.fillText.apply(context,args);}
if(this.drawStroke){context.strokeText.apply(context,args);}},measureWidth:function(canvas){if(!(canvas instanceof Curly.Canvas)){throw new Curly.Canvas.Error('Invalid canvas instance given');}
return canvas.applyState().getCtx().measureText(this.text).width;}});