text: (function(){
  	"use strict";
  
  	var root = this,
  		Chart = root.Chart,
  		helpers = Chart.helpers;
  
  	var defaultConfig = {
  
  		///Boolean - Whether grid lines are shown across the chart
  		scaleShowGridLines : true,
  
  		//String - Colour of the grid lines
  		scaleGridLineColor : "rgba(0,0,0,.05)",
  
  		//Number - Width of the grid lines
  		scaleGridLineWidth : 1,
  
  		//Boolean - Whether to show horizontal lines (except X axis)
  		scaleShowHorizontalLines: true,
  
  		//Boolean - Whether to show vertical lines (except Y axis)
  		scaleShowVerticalLines: true,
  
  		//Boolean - Whether the line is curved between points
  		bezierCurve : true,
  
  		//Number - Tension of the bezier curve between points
  		bezierCurveTension : 0.4,
  
  		//Boolean - Whether to show a dot for each point
  		pointDot : true,
  
  		//Number - Radius of each point dot in pixels
  		pointDotRadius : 4,
  
  		//Number - Pixel width of point dot stroke
  		pointDotStrokeWidth : 1,
  
  		//Number - amount extra to add to the radius to cater for hit detection outside the drawn point
  		pointHitDetectionRadius : 20,
  
  		//Boolean - Whether to show a stroke for datasets
  		datasetStroke : true,
  
  		//Number - Pixel width of dataset stroke
  		datasetStrokeWidth : 2,
  
  		//Boolean - Whether to fill the dataset with a colour
  		datasetFill : true,
  
  		//String - A legend template
  		legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>"
  
  	};
  
  
  	Chart.Type.extend({
  		name: "Line",
  		defaults : defaultConfig,
  		initialize:  function(data){
  			//Declare the extension of the default point, to cater for the options passed in to the constructor
  			this.PointClass = Chart.Point.extend({
  				strokeWidth : this.options.pointDotStrokeWidth,
  				radius : this.options.pointDotRadius,
  				display: this.options.pointDot,
  				hitDetectionRadius : this.options.pointHitDetectionRadius,
  				ctx : this.chart.ctx,
  				inRange : function(mouseX){
  					return (Math.pow(mouseX-this.x, 2) < Math.pow(this.radius + this.hitDetectionRadius,2));
  				}
  			});
  
  			this.datasets = [];
  
  			//Set up tooltip event on the chart
  			if (this.options.showTooltips){
  				helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
  					var activePoints = (evt.type !== 'mouseout') ? this.getPointsAtEvent(evt) : [];
  					this.eachPoints(function(point){
  						point.restore(['fillColor', 'strokeColor']);
  					});
  					helpers.each(activePoints, function(activePoint){
  						activePoint.fillColor = activePoint.highlightFill;
  						activePoint.strokeColor = activePoint.highlightStroke;
  					});
  					this.showTooltip(activePoints);
  				});
  			}
  
  			//Iterate through each of the datasets, and build this into a property of the chart
  			helpers.each(data.datasets,function(dataset){
  
  				var datasetObject = {
  					label : dataset.label || null,
  					fillColor : dataset.fillColor,
  					strokeColor : dataset.strokeColor,
  					pointColor : dataset.pointColor,
  					pointStrokeColor : dataset.pointStrokeColor,
  					points : []
  				};
  
  				this.datasets.push(datasetObject);
  
  
  				helpers.each(dataset.data,function(dataPoint,index){
  					//Add a new point for each piece of data, passing any required data to draw.
  					datasetObject.points.push(new this.PointClass({
  						value : dataPoint,
  						label : data.labels[index],
  						datasetLabel: dataset.label,
  						strokeColor : dataset.pointStrokeColor,
  						fillColor : dataset.pointColor,
  						highlightFill : dataset.pointHighlightFill || dataset.pointColor,
  						highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
  					}));
  				},this);
  
  				this.buildScale(data.labels);
  
  
  				this.eachPoints(function(point, index){
  					helpers.extend(point, {
  						x: this.scale.calculateX(index),
  						y: this.scale.endPoint
  					});
  					point.save();
  				}, this);
  
  			},this);
  
  
  			this.render();
  		},
  		update : function(){
  			this.scale.update();
  			// Reset any highlight colours before updating.
  			helpers.each(this.activeElements, function(activeElement){
  				activeElement.restore(['fillColor', 'strokeColor']);
  			});
  			this.eachPoints(function(point){
  				point.save();
  			});
  			this.render();
  		},
  		eachPoints : function(callback){
  			helpers.each(this.datasets,function(dataset){
  				helpers.each(dataset.points,callback,this);
  			},this);
  		},
  		getPointsAtEvent : function(e){
  			var pointsArray = [],
  				eventPosition = helpers.getRelativePosition(e);
  			helpers.each(this.datasets,function(dataset){
  				helpers.each(dataset.points,function(point){
  					if (point.inRange(eventPosition.x,eventPosition.y)) pointsArray.push(point);
  				});
  			},this);
  			return pointsArray;
  		},
  		buildScale : function(labels){
  			var self = this;
  
  			var dataTotal = function(){
  				var values = [];
  				self.eachPoints(function(point){
  					values.push(point.value);
  				});
  
  				return values;
  			};
  
  			var scaleOptions = {
  				templateString : this.options.scaleLabel,
  				height : this.chart.height,
  				width : this.chart.width,
  				ctx : this.chart.ctx,
  				textColor : this.options.scaleFontColor,
  				fontSize : this.options.scaleFontSize,
  				fontStyle : this.options.scaleFontStyle,
  				fontFamily : this.options.scaleFontFamily,
  				valuesCount : labels.length,
  				beginAtZero : this.options.scaleBeginAtZero,
  				integersOnly : this.options.scaleIntegersOnly,
  				calculateYRange : function(currentHeight){
  					var updatedRanges = helpers.calculateScaleRange(
  						dataTotal(),
  						currentHeight,
  						this.fontSize,
  						this.beginAtZero,
  						this.integersOnly
  					);
  					helpers.extend(this, updatedRanges);
  				},
  				xLabels : labels,
  				font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
  				lineWidth : this.options.scaleLineWidth,
  				lineColor : this.options.scaleLineColor,
  				showHorizontalLines : this.options.scaleShowHorizontalLines,
  				showVerticalLines : this.options.scaleShowVerticalLines,
  				gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
  				gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
  				padding: (this.options.showScale) ? 0 : this.options.pointDotRadius + this.options.pointDotStrokeWidth,
  				showLabels : this.options.scaleShowLabels,
  				display : this.options.showScale
  			};
  
  			if (this.options.scaleOverride){
  				helpers.extend(scaleOptions, {
  					calculateYRange: helpers.noop,
  					steps: this.options.scaleSteps,
  					stepValue: this.options.scaleStepWidth,
  					min: this.options.scaleStartValue,
  					max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
  				});
  			}
  
  
  			this.scale = new Chart.Scale(scaleOptions);
  		},
  		addData : function(valuesArray,label){
  			//Map the values array for each of the datasets
  
  			helpers.each(valuesArray,function(value,datasetIndex){
  				//Add a new point for each piece of data, passing any required data to draw.
  				this.datasets[datasetIndex].points.push(new this.PointClass({
  					value : value,
  					label : label,
  					x: this.scale.calculateX(this.scale.valuesCount+1),
  					y: this.scale.endPoint,
  					strokeColor : this.datasets[datasetIndex].pointStrokeColor,
  					fillColor : this.datasets[datasetIndex].pointColor
  				}));
  			},this);
  
  			this.scale.addXLabel(label);
  			//Then re-render the chart.
  			this.update();
  		},
  		removeData : function(){
  			this.scale.removeXLabel();
  			//Then re-render the chart.
  			helpers.each(this.datasets,function(dataset){
  				dataset.points.shift();
  			},this);
  			this.update();
  		},
  		reflow : function(){
  			var newScaleProps = helpers.extend({
  				height : this.chart.height,
  				width : this.chart.width
  			});
  			this.scale.update(newScaleProps);
  		},
  		draw : function(ease){
  			var easingDecimal = ease || 1;
  			this.clear();
  
  			var ctx = this.chart.ctx;
  
  			// Some helper methods for getting the next/prev points
  			var hasValue = function(item){
  				return item.value !== null;
  			},
  			nextPoint = function(point, collection, index){
  				return helpers.findNextWhere(collection, hasValue, index) || point;
  			},
  			previousPoint = function(point, collection, index){
  				return helpers.findPreviousWhere(collection, hasValue, index) || point;
  			};
  
  			this.scale.draw(easingDecimal);
  
  
  			helpers.each(this.datasets,function(dataset){
  				var pointsWithValues = helpers.where(dataset.points, hasValue);
  
  				//Transition each point first so that the line and point drawing isn't out of sync
  				//We can use this extra loop to calculate the control points of this dataset also in this loop
  
  				helpers.each(dataset.points, function(point, index){
  					if (point.hasValue()){
  						point.transition({
  							y : this.scale.calculateY(point.value),
  							x : this.scale.calculateX(index)
  						}, easingDecimal);
  					}
  				},this);
  
  
  				// Control points need to be calculated in a seperate loop, because we need to know the current x/y of the point
  				// This would cause issues when there is no animation, because the y of the next point would be 0, so beziers would be skewed
  				if (this.options.bezierCurve){
  					helpers.each(pointsWithValues, function(point, index){
  						var tension = (index > 0 && index < pointsWithValues.length - 1) ? this.options.bezierCurveTension : 0;
  						point.controlPoints = helpers.splineCurve(
  							previousPoint(point, pointsWithValues, index),
  							point,
  							nextPoint(point, pointsWithValues, index),
  							tension
  						);
  
  						// Prevent the bezier going outside of the bounds of the graph
  
  						// Cap puter bezier handles to the upper/lower scale bounds
  						if (point.controlPoints.outer.y > this.scale.endPoint){
  							point.controlPoints.outer.y = this.scale.endPoint;
  						}
  						else if (point.controlPoints.outer.y < this.scale.startPoint){
  							point.controlPoints.outer.y = this.scale.startPoint;
  						}
  
  						// Cap inner bezier handles to the upper/lower scale bounds
  						if (point.controlPoints.inner.y > this.scale.endPoint){
  							point.controlPoints.inner.y = this.scale.endPoint;
  						}
  						else if (point.controlPoints.inner.y < this.scale.startPoint){
  							point.controlPoints.inner.y = this.scale.startPoint;
  						}
  					},this);
  				}
  
  
  				//Draw the line between all the points
  				ctx.lineWidth = this.options.datasetStrokeWidth;
  				ctx.strokeStyle = dataset.strokeColor;
  				ctx.beginPath();
  
  				helpers.each(pointsWithValues, function(point, index){
  					if (index === 0){
  						ctx.moveTo(point.x, point.y);
  					}
  					else{
  						if(this.options.bezierCurve){
  							var previous = previousPoint(point, pointsWithValues, index);
  
  							ctx.bezierCurveTo(
  								previous.controlPoints.outer.x,
  								previous.controlPoints.outer.y,
  								point.controlPoints.inner.x,
  								point.controlPoints.inner.y,
  								point.x,
  								point.y
  							);
  						}
  						else{
  							ctx.lineTo(point.x,point.y);
  						}
  					}
  				}, this);
  
  				ctx.stroke();
  
  				if (this.options.datasetFill && pointsWithValues.length > 0){
  					//Round off the line by going to the base of the chart, back to the start, then fill.
  					ctx.lineTo(pointsWithValues[pointsWithValues.length - 1].x, this.scale.endPoint);
  					ctx.lineTo(pointsWithValues[0].x, this.scale.endPoint);
  					ctx.fillStyle = dataset.fillColor;
  					ctx.closePath();
  					ctx.fill();
  				}
  
  				//Now draw the points over the line
  				//A little inefficient double looping, but better than the line
  				//lagging behind the point positions
  				helpers.each(pointsWithValues,function(point){
  					point.draw();
  				});
  			},this);
  		}
  	});
  
  
  }).call(this);
  