Raphael.fn.matchDrop = function(id,width,height,onScore,onLevelUp){
	var score = 0; 
	var largestGroup = 0;
	var moves =0;
	var colors = ["#de3c29","#c9932d","#007d46","#224360","#912220","#0087fa"];
	var hcolors = ["f87060","#f0c779","#26a26b","#487093","#a7413f","#6eabdf"];
	var numColors = 3; 
	var columns;
	var paper = Raphael(id,width,height);
	var groupSizes = {};
	var groupsRemaining = true; 
	var blocksRemaining = 0; 
	var background = "#252522";
	var nextButton; 
	var text; 
	var textAttr = {
		"font-size":20,
		"fill":"#fff",
		"stroke-width":0,
		"font-family":"Lobster"
	}
			
	var xCount = 15,
		yCount = 15,
		padding =30,
		blockWidth; 
	var currentLevel =0;
	var levels = [
		{size:15,colors:3},
		{size:15,colors:4},
		{size:15,colors:4},
		{size:20,colors:3},
		{size:20,colors:4},
		{size:20,colors:4},
		{size:20,colors:5},
		{size:20,colors:6},
		{size:25,colors:3},
		{size:25,colors:4},
		{size:25,colors:4},
		{size:25,colors:5},
		{size:25,colors:6},
		{size:25,colors:1}
	];
	
	//go to next level
	function nextLevel(){
		currentLevel = currentLevel + 1;
		if (currentLevel == levels.length){
			if (text) text.attr("text","You Won!\nWell Done. Thank's for Playing!")
			else text = paper.text(width/2,padding,"You Won!\nWell Done. Thank's for Playing!");
			text.attr(textAttr);
		}else{
			var level = levels[currentLevel];
			numColors = level.colors; 
			xCount = level.size;
			yCount = level.size;
			onLevelUp(currentLevel+1);
			
			setTimeout(function(){
				if (text) text.attr("text","");
				text = paper.text(width/2,padding,"Level Completed");
				text.attr(textAttr);
				setTimeout(function(){
					var text = paper.text(width/2,padding + 50,"Score: " + score);
					text.attr(textAttr);			
					setTimeout(function(){
						var text;
						if (blocksRemaining > 0){
							text = paper.text(width/2,padding + 100,"Remaining Blocks: " + (blocksRemaining*-100) + " Points" );
							score += blocksRemaining*-100;
						}else{
							text = paper.text(width/2,padding + 100,"No Remaining Blocks: 1000 Points");
							score += 1000;
						}
						text.attr(textAttr);
						setTimeout(function(){
							var remainText = paper.text(width/2,padding + 150,"Moves Used: " + (1000 - moves*10) + " Points");
							score += (1000 - moves*10)
							remainText.attr(textAttr);
							setTimeout(function(){
								var text = paper.text(width/2,padding + 200,"Final Score: " + score);
								onScore(score,moves,largestGroup);
								var buttonText;
								nextButton = paper.rect(width/2-100,height/2+30,200,30,5);
								nextButton.attr({"fill":"#c9932d","stroke-width":0});
								if (score < 0){
									currentLevel = 0;		
									score = 0;
									var level = levels[currentLevel];
									numColors = level.colors; 
									xCount = level.size;
									yCount = level.size;
									onLevelUp(currentLevel+1);								
									buttonText = paper.text(width/2,height/2+47,"Try Again");
									nextButton.click(setup);
									buttonText.click(setup);
								}else{
									buttonText = paper.text(width/2,height/2+47,"Next Level");
									nextButton.click(setup);
									buttonText.click(setup);
								}
								buttonText.attr(textAttr);	
								text.attr(textAttr);							
							},700);
						},700);
					},700);
				},700);
				
			},1000);
		}//end next turn stuff
	} 
	
	//find groups of colors
	function findGroups(){
		blocksRemaining = 0; 
		groupsRemaining = false; 
		for (var i = 0,il=columns.length; i < il ; i ++){
			for (var j = 0,jl=columns[i].length; j < jl ; j ++){
				blocksRemaining++;
				columns[i][j].findGroups(i*yCount + j);
			}
		}
		if (!groupsRemaining){
			nextLevel();
		}
	}	
	
	//create blocks
	function setup(){
		paper.clear();
		columns = []; 
		largestGroup = 0; 
		moves = 0; 
		blockWidth = width/xCount - 2*padding/xCount; 
		//create the text
		text = paper.text(width/2,padding,"");
		text.attr(textAttr);
				
		for (var i = 0,il=xCount; i < il ; i ++){
			columns[i] = []; 
			for (var j = 0,jl=yCount; j < jl ; j ++){
				var color = Math.floor(Math.random()*numColors); 
				var block = paper.rect(i*blockWidth+padding,height-j*blockWidth-padding,blockWidth-2,blockWidth-2,5);
				block.attr({fill:colors[color],"stroke-width":2,"stroke":background});
				block.type = color; 
				block.column = i; 
				block.row = j;
				block.id = i*yCount+j;
				block.downQ = 0;
				block.leftQ = 0;
				block.marked= false; 
				
				block.findGroups = function (groupNumber){ 
					if (this.marked) return;
					var i = this.column; 
					var j = this.row; 
					this.marked=true;
					this.group = groupNumber;
					if (!groupSizes[groupNumber]) groupSizes[groupNumber] = 0; 
					groupSizes[groupNumber]++;
					if (groupSizes[groupNumber] > 1) groupsRemaining = true; 
					var neighbor = [];
					if (j < columns[i].length) neighbor.push(columns[i][j+1]);
					if (j > 0) neighbor.push(columns[i][j-1]);
					if (i > 0) neighbor.push(columns[i-1][j]);
					if (i < columns.length-1) neighbor.push(columns[i+1][j]);
					for (var k =0; k < neighbor.length; k++){
						if (neighbor[k])
						if (neighbor[k].type == this.type)
							neighbor[k].findGroups(groupNumber);
					}
				}
				
				block.click(function(){
					var size = groupSizes[this.group]; 
					if (size < 2){ 
						return;
					}
					text.attr({"text":"","font-size":1});
					if (size > 7)
						if (size < 15)  text.attr({"text":"Good Job! x2"});
						else if (size < 20)  text.attr({"text":"Great Job! x4"});
						else if (size < 25)  text.attr({"text":"Oh my, Quite Excellent! x8"});
						else if (size < 30) text.attr({"text":"Oh, so many Indeed! x16"});
						else text.attr({"text":"Force of a Thousand Suns!!! x32"});
					text.animate({"font-size":20,"fill":"#fff","y":padding},300,"<");  
					
					
					var thisScore = size
					if (size >13 && size < 15) thisScore *=2;
					if (size >15 && size< 20) thisScore *=4;
					if (size >20 && size< 25) thisScore *=8;
					if (size >25 && size< 30) thisScore *=16;				
					if (size > 30) thisScore *=32;
					score += thisScore;
					moves ++; 
					largestGroup = Math.max(largestGroup,size)
					onScore(score,moves,largestGroup); 
					
					var group = [];
					//find the group members and mark all upper blocks to come down
					for (var k = 0,kl=columns.length; k < kl ; k ++){
						var inColumn = 0; 
						var column = columns[k]; 
						for (var l = 0,ll=column.length; l < ll ; l ++){
							if (column[l].group == this.group){
								group.push(column[l]);
								for (var m = l+1; m < columns[k].length; m++){
									column[m].downQ += blockWidth; 
									column[m].row -= 1;
								}
								inColumn++;
							}
						}
						//if column is gone, move everyone over
						if (inColumn == column.length){
							for (i = k+1,il=columns.length;i<il;i++){
								for (j = 0,jl=columns[i].length;j<jl;j++){
									var block = columns[i][j];
									block.column -= 1;
									block.leftQ = -1*blockWidth; 
								}
							}
						}
						
					}
	
					//move all blocks down
					for (var k = 0,kl=columns.length; k < kl ; k ++){
						var column = columns[k]; 
						for (var l = 0,ll=column.length; l < ll ; l ++){
							var curY = height - l * blockWidth-padding;
							var block = column[l];
							var downQ = block.downQ; 
							block.animate({y:curY+downQ},500,"bounce");
							block.downQ = 0;
							block.marked = false;
						}
					}
	
						
					//remove blocks and columns
					for (var i =0,il = group.length ; i < il ; i++){
						var block = group[i];
						var columnIndex= block.column;
						var column = columns[columnIndex];
						column.splice(block.row,1);
						block.explode();
						if (column.length == 0){
							columns.splice(columnIndex,1);
						}
					}
					
					//move all columns over if needed  
					for (var k = 0,kl=columns.length; k < kl ; k ++)
						for (var l = 0,ll=columns[k].length; l < ll ; l ++){
							var block = columns[k][l]; 
							var leftQ = block.leftQ;
							if (leftQ < 0){
								var curX = k * blockWidth+padding;
								leftQ += blockWidth;		
								block.animate({x:curX+leftQ},500,"<");
								block.leftQ = 0;
								block.marked = false;
							}
						}
					
					//find new groups resulting from the moves
					groupSizes = {}; 
					findGroups();
				});
	
				block.mouseout(function(){
					for (var i = 0,il=columns.length; i < il ; i ++){
						for (var j = 0,jl=columns[i].length; j < jl ; j ++){	
							if (columns[i][j].group == this.group)
								columns[i][j].attr({"fill":colors[this.type],"stroke":background});
						}
					}
				});			
				
				block.mouseover(function(){
					for (var i = 0,il=columns.length; i < il ; i ++){
						for (var j = 0,jl=columns[i].length; j < jl ; j ++){	
							if (columns[i][j].group == this.group)
								columns[i][j].attr({"fill":hcolors[this.type],stroke:"#fff","stroke-width":2});
						}
					}
				});
				
				block.explode = function(){
					var x = this.attr("x");
					var y = this.attr("y");
					var speed = 25;
					var minspeed = 15; 
					var gravity = 0.1; 
					var quart = blockWidth*0.5;
					var bitAttr = {"fill":colors[this.type],"stroke-width":0};
					//create build four blocks in place
					var bits = []; 
					bits[0] = paper.rect(x,y,quart,quart,3);
					bits[1] = paper.rect(x+quart,y,quart,quart,3); 
					for (var i = 0; i<2;i++){
						var bit = bits[i]; 
						bit.attr(bitAttr);				
						bit.speed = Math.random()*speed+minspeed;
						bit.angle = Math.random()*3.14*2;
					}
					var life = blockWidth;
					//send them off at random angles and speeds
					var animate = setInterval(function(){
						for (var i = 0; i<2;i++){
							var bit = bits[i];
							
							var curX = bit.attr("x");
							var curY = bit.attr("y");
							
							if (bit.angle > 1.57)
							if (bit.angle > 4.71){
								bit.angle += gravity;
								if (bit.angle > 7.85) bit.angle = 1.57;
							} else{ 
								bit.angle -= gravity
							}
							
							life--;
							if (life <= 0){
								bit.remove();
								clearInterval(animate); 
							}
								
							bit.attr({
								x:(curX + bit.speed*Math.cos(bit.angle)),
								y:(curY + bit.speed*Math.sin(bit.angle)),
								width:life,
								height:life
								});
						}
					},60);
					this.remove();
				}
				columns[i][j] = block;
			}
			text.toFront();
		}
		findGroups();
	}//end setup
	
	window.onload = function() {
		document.onselectstart = function() {return false;} // ie
		document.onmousedown = function() {return false;} // mozilla
	}
	setup(); 
}

