<!-- hide this script from non-javascript-enabled browsers
/*
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
* DO NOT MAKE ANY CHANGES TO THIS FILE!                                       
*	CONTACT Joe Frausto Jr. TO REQUEST A CHANGE TO THIS FILE                    
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
*  
* ------------------------------------------------------------------------------------ 
*/

// global variables
var ccell;						// current cell for cursor
var Tempboard=new Array(81);		// board on display
var board=new Array(81);		// board on display
var digit=new Array('1','2','3','4','5','6','7','8','9','*','*','*','*','*','*',' ');
var digit_mask=0x0000000F;		// displayed digit mask
var solve_mask=0x000000F0;		// solution digit mask
var allow_mask=0x0001FF00;		// digits allowed in this cell mask
var locks_mask=0x00020000;		// cell locked mask
var allow_bits=new Array(0x00100,0x00200,0x00400,0x00800,0x01000,0x02000,0x04000,0x08000,0x10000);
var lock_flag=0x00020000;		// cell locked
var box_index=new Array(9);		// look-up table for boxes
var col_index=new Array(9);		// look-up table for columns
var row_index=new Array(9);		// look-up table for rows
var solved;						// flag if solution found

var animthread=null;
var	animtrigger=0;
var spiral=new Array(0,1,2,3,4,5,6,7,8,17,26,35,44,53,62,71,80,79,78,77,76,75,74,73,72,63,54,45,36,27,18,9,10,11,12,13,14,15,16,25,34,43,52,61,70,69,68,67,66,65,64,55,46,37,28,19,20,21,22,23,24,33,42,51,60,59,58,57,56,47,38,29,30,31,32,41,50,49,48,39,40);
var target0=new Array(40,40);
var target1=new Array(30,31,32,41,50,49,48,39);
var target2=new Array(20,21,22,23,24,33,42,51,60,59,58,57,56,47,38,29);
var target3=new Array(10,11,12,13,14,15,16,25,34,43,52,61,70,69,68,67,66,65,64,55,46,37,28,19);
var target4=new Array(0,1,2,3,4,5,6,7,8,17,26,35,44,53,62,71,80,79,78,77,76,75,74,73,72,63,54,45,36,27,18,9);

// random number generator
var today=new Date();
var seed=today.getTime();
function rnd() {
	seed = (seed*9301+49297) % 233280;
	return seed/(233280.0);
};
function rand(number) {
	return Math.floor(rnd()*number);
};

// clear back to empty
function doclear()
{
	var i;

	for (i=0;i<81;i++) {
		Tempboard[i] = ' ';
//		var pfield=document.getElementById("c"+i);
//		pfield.className="digit";
//		pfield.style.backgroundColor="#eeeeee";
//		pfield.value=' ';
		board[i]=allow_mask | solve_mask | digit_mask;
	}
	solved=0;
}

// once only initialisation
function initialise()
{
	// initialise quick indexes
	box_index[0]=new Array(0,1,2,9,10,11,18,19,20);
	box_index[1]=new Array(3,4,5,12,13,14,21,22,23);
	box_index[2]=new Array(6,7,8,15,16,17,24,25,26);
	box_index[3]=new Array(27,28,29,36,37,38,45,46,47);
	box_index[4]=new Array(30,31,32,39,40,41,48,49,50);
	box_index[5]=new Array(33,34,35,42,43,44,51,52,53);
	box_index[6]=new Array(54,55,56,63,64,65,72,73,74);
	box_index[7]=new Array(57,58,59,66,67,68,75,76,77);
	box_index[8]=new Array(60,61,62,69,70,71,78,79,80);
	row_index[0]=new Array(0,1,2,3,4,5,6,7,8);
	row_index[1]=new Array(9,10,11,12,13,14,15,16,17);
	row_index[2]=new Array(18,19,20,21,22,23,24,25,26);
	row_index[3]=new Array(27,28,29,30,31,32,33,34,35);
	row_index[4]=new Array(36,37,38,39,40,41,42,43,44);
	row_index[5]=new Array(45,46,47,48,49,50,51,52,53);
	row_index[6]=new Array(54,55,56,57,58,59,60,61,62);
	row_index[7]=new Array(63,64,65,66,67,68,69,70,71);
	row_index[8]=new Array(72,73,74,75,76,77,78,79,80);
	col_index[0]=new Array(0,9,18,27,36,45,54,63,72);
	col_index[1]=new Array(1,10,19,28,37,46,55,64,73);
	col_index[2]=new Array(2,11,20,29,38,47,56,65,74);
	col_index[3]=new Array(3,12,21,30,39,48,57,66,75);
	col_index[4]=new Array(4,13,22,31,40,49,58,67,76);
	col_index[5]=new Array(5,14,23,32,41,50,59,68,77);
	col_index[6]=new Array(6,15,24,33,42,51,60,69,78);
	col_index[7]=new Array(7,16,25,34,43,52,61,70,79);
	col_index[8]=new Array(8,17,26,35,44,53,62,71,80);

	// clear board
	doclear();

	// restore from cookie
	restoreboard();

	// display cursor
	ccell=0;
//	var pfield=document.getElementById("c"+ccell);
	if (board[ccell]&lock_flag)
	{
	}
//		pfield.className="digitlock";
//	else
//		pfield.className="digit";
//	pfield.style.backgroundColor="#eeddcc";
//	pfield.focus();

	// trap key presses
	document.onkeydown=kbdhandler;

}

// get row index from cell number
function getrow(cell)
{
	return(Math.floor(cell/9));
}

// get column from cell number
function getcol(cell)
{
	return(Math.floor(cell%9));
}

// get box from cell number
function getbox(cell)
{
	var row=getrow(cell);
	var col=getcol(cell);

	return(Math.floor(3*Math.floor(row/3)+Math.floor(col/3)));
}

// move cursor to cell
function cell(cc)
{
//	var pfield=document.getElementById("c"+ccell);
	if (board[ccell]&lock_flag)
	{
	}
//		pfield.className="digitlock";
//	else
//		pfield.className="digit";
//	pfield.style.backgroundColor="#eeeeee";
	ccell=cc;
//	pfield=document.getElementById("c"+ccell);
	if (board[ccell]&lock_flag)
	{
	}
//		pfield.className="digitlock";
//	else
//		pfield.className="digit";
//	pfield.style.backgroundColor="#eeddcc";
//	pfield.focus();
}

// move hint highlight to cell
function cellblink(cc)
{
//	var pfield=document.getElementById("c"+ccell);
	if (board[ccell]&lock_flag)
	{
	}
//		pfield.className="digitlock";
//	else
//		pfield.className="digit";
//	pfield.style.backgroundColor="#eeeeee";
	ccell=cc;
//	var pfield=document.getElementById("c"+ccell);
	if (board[ccell]&lock_flag)
	{
	}
//		pfield.className="digitlock";
//	else
//		pfield.className="digit";
//	pfield.style.backgroundColor="#ccddee";
//	pfield.focus();
}

// enter a digit from digit buttons
function dodigit(num)
{
//	var pfield=document.getElementById("c"+ccell);
	if (checklegal(board,ccell,num)&&!(board[ccell]&lock_flag)) {
//		pfield.value=digit[num];
		Tempboard[ccell]=digit[num];
		board[ccell] = (board[ccell] & ~digit_mask) | num;
		solved=0;
		if (animtrigger && checksolution()) {
			animthread=setInterval("animate()",60);
			setTimeout("noanimate()",20000);
			animtrigger=0;
		}
	}
	else if (!(board[ccell]&lock_flag)) {
//		pfield.value=' ';
		Tempboard[ccell]=' ';
		board[ccell] |= digit_mask;
		solved=0;
		dobeep();
	}
	cell(ccell);
}

// enter a digit from keyboard
function kbdhandler(e)
{
//	var pfield=document.getElementById("c"+ccell);

	if (!e) e=window.event;
	var chr = String.fromCharCode(e.keyCode);

	if (('1'<=chr)&&(chr <='9')) {
		var d=chr.charCodeAt(0)-49;
		dodigit(d);
	}
	else if (('a'<=chr)&&(chr <='i')) {
		var d=chr.charCodeAt(0)-97;
		dodigit(d);
	}
	else if ((chr==' ')||(e.keyCode==46)||(e.keyCode==8)) {
		if ((board[ccell]&lock_flag)==0) {
//			pfield.value=' ';
			Tempboard[ccell]=' ';
			board[ccell] |= digit_mask;
			cell(ccell);
			solved=0;
		}
	}
	else if (chr=='\x25') {
		// left arrow
		var cc=ccell-1;
		if (cc<0) {
			cc += 81;
		}
		cell(cc);
	}
	else if (chr=='\x26') {
		// up arrow
		var cc=ccell-9;
		if (cc<0) {
			if (cc==-9)
				cc = 80;
			else
				cc += 80;
		}
		cell(cc);
	}
	else if (chr=='\x27') {
		// right arrow
		var cc=ccell+1;
		if (cc>80) {
			cc -= 81;
		}
		cell(cc);
	}
	else if (chr=='\x28') {
		// down arrow
		var cc=ccell+9;
		if (cc > 80) {
			if (cc==89)
				cc=0;
			else
				cc -= 80;
		}
		cell(cc);
	}
//	else if (chr==0)
//		alert("Got key code="+e.keyCode);
//	else
//		alert("Got key code="+e.keyCode+" char="+chr);
//	pfield.focus();
}

// check user input is allowed
// note that we allow users to enter incorrect digits
// that happen to still be legal according to the rules
function checklegal(board,cc,d)
{
	var hold=board[cc];
	var i,j;
	board[cc] |= digit_mask;

	// check row
	var row=getrow(cc);
	for (j=0;j<9;j++)
		if ((board[row_index[row][j]]&digit_mask)==d) {
			board[cc]=hold;
			return(0);
		}

	// check column
	var col=getcol(cc);
	for (j=0;j<9;j++)
		if ((board[col_index[col][j]]&digit_mask)==d) {
			board[cc]=hold;
			return(0);
		}

	// check box
	var box=getbox(cc);
	for (j=0;j<9;j++)
		if ((board[box_index[box][j]]&digit_mask)==d) {
			board[cc]=hold;
			return(0);
		}

	// OK
	board[cc]=hold;
	return(1);
}

// lock the currently displayed digits
function dolock()
{
	var i;

	for (i=0;i<81;i++) {
		if ((board[i]&digit_mask)<9) {
//			var pfield=document.getElementById("c"+i);
//			pfield.className="digitlock";
			board[i] |= lock_flag;
		}
	}
}

// reset the board to the locked digits only
function doreset()
{
	var i;

	for (i=0;i<81;i++) {
		if (!(board[i]&lock_flag)) {
//			var pfield=document.getElementById("c"+i);
//			pfield.value=' ';
			Tempboard[i]=' ';
			board[i] |= digit_mask;
		}
	}
}

// play a warning beep
function dobeep() {
	var thissound=document.getElementById("beep");
	thissound.Play();
}

// check solution
function checksolution()
{
	var	i,sum;

	// check rows
	for (i=0;i<9;i++) {
		sum=0;
		for (j=0;j<9;j++) sum += board[row_index[i][j]] & digit_mask;
		if (sum!=36) return(0);
	}
	// check cols
	for (i=0;i<9;i++) {
		sum=0;
		for (j=0;j<9;j++) sum += board[col_index[i][j]] & digit_mask;
		if (sum!=36) return(0);
	}
	// check boxes
	for (i=0;i<9;i++) {
		sum=0;
		for (j=0;j<9;j++) sum += board[box_index[i][j]] & digit_mask;
		if (sum!=36) return(0);
	}
	return(1);
}

// set a digit into a board cell
function setdigit(cc,num)
{
//	var pfield=document.getElementById("c"+cc);
//	if (board[cc] & lock_flag)
//		pfield.className="digitlock";
//	else
//		pfield.className="digit";
//	pfield.value=digit[num];
	Tempboard[cc]=digit[num];
	board[cc] = (board[cc] & ~digit_mask) | num;
}

// check the contents of all boxes
function boxcheck(board)
{
	var i,j,d,sum,last,last2,last3;

	for (i=0;i<9;i++) {
		for (d=0;d<9;d++) {
			sum=0;
			last=-1;
			last2=-1;
			last3=-1;
			for (j=0;j<9;j++) {
				if (board[box_index[i][j]]&allow_bits[d]) {
					sum++;
					last3=last2;
					last2=last;
					last=box_index[i][j];
				}
				else
					sum += ((board[box_index[i][j]] & solve_mask)==(d << 4)) ? 1: 0;
			}
			// if #possible is 0 then fail
			if (sum==0) return(0);
			// if #possible is 1 then fix it in solution
			if ((sum==1)&&(last>=0)) {
				if (!setallowed(board,last,d)) return(0);
			}
			// if #possible is 2 then if both on same row, can't be elsewhere on row
			if ((sum==2)&&(last>=0)&&(last2>=0)&&(getrow(last)==getrow(last2))) {
				for (j=0;j<9;j++) {
					var c=row_index[getrow(last)][j];
					if ((c!=last)&&(c!=last2)) {
						if (board[c]&allow_bits[d]) {
							board[c] &= ~allow_bits[d];
							if ((board[c]&allow_mask)==0) return(0);
						}
					}
				}
			}
			// if #possible is 2 then if both on same col, can't be elsewhere on col
			if ((sum==2)&&(last>=0)&&(last2>=0)&&(getcol(last)==getcol(last2))) {
				for (j=0;j<9;j++) {
					var c=col_index[getcol(last)][j];
					if ((c!=last)&&(c!=last2)) {
						if (board[c]&allow_bits[d]) {
							board[c] &= ~allow_bits[d];
							if ((board[c]&allow_mask)==0) return(0);
						}
					}
				}
			}
			// if #possible is 3 then if all on same row, can't be elsewhere on row
			if ((sum==3)&&(last>=0)&&(last2>=0)&&(last3>=0)&&(getrow(last)==getrow(last2))&&(getrow(last)==getrow(last3))) {
				for (j=0;j<9;j++) {
					c=row_index[getrow(last)][j];
					if ((c!=last)&&(c!=last2)&&(c!=last3)) {
						if (board[c]&allow_bits[d]) {
							board[c] &= ~allow_bits[d];
							if ((board[c]&allow_mask)==0) return(0);
						}
					}
				}
			}
			// if #possible is 3 then if all on same col, can't be elsewhere on col
			if ((sum==3)&&(last>=0)&&(last2>=0)&&(last3>=0)&&(getcol(last)==getcol(last2))&&(getcol(last)==getcol(last3))) {
				for (j=0;j<9;j++) {
					c=col_index[getcol(last)][j];
					if ((c!=last)&&(c!=last2)&&(c!=last3)) {
						if (board[c]&allow_bits[d]) {
							board[c] &= ~allow_bits[d];
							if ((board[c]&allow_mask)==0) return(0);
						}
					}
				}
			}
		}
	}
	return(1);
}

// check the contents of all rows
function rowcheck(board)
{
	var i,j,d,sum,last;

	for (i=0;i<9;i++) {
		for (d=0;d<9;d++) {
			sum=0;
			last=-1;
			for (j=0;j<9;j++) {
				if (board[row_index[i][j]]&allow_bits[d]) {
					sum++;
					last=j;
				}
				else
					sum += ((board[row_index[i][j]] & solve_mask)==(d << 4)) ? 1: 0;
			}
			if (sum==0) return(0);
			if ((sum==1)&&(last>=0)) {
				if (!setallowed(board,row_index[i][last],d)) return(0);
			}
		}
	}
	return(1);
}

// check the contents of all columns
function colcheck(board)
{
	var i,j,d,sum,last;

	for (i=0;i<9;i++) {
		for (d=0;d<9;d++) {
			sum=0;
			last=-1;
			for (j=0;j<9;j++) {
				if (board[col_index[i][j]]&allow_bits[d]) {
					sum++;
					last=j;
				}
				else
					sum += ((board[col_index[i][j]] & solve_mask)==(d << 4)) ? 1: 0;
			}
			if (sum==0) return(0);
			if ((sum==1)&&(last>=0)) {
				if (!setallowed(board,col_index[i][last],d)) return(0);
			}
		}
	}
	return(1);
}

// set a digit into a board, clearing allowed flags elsewhere
function setallowed(board,cc,num)
{
	var i,j,k,l,d;
	var s;

	// clear alternatives in this cell
	board[cc] &= ~allow_mask;
	// and set value as solution
	board[cc] = (board[cc] & ~solve_mask) | (num << 4);

	// clear this digit on same row

	var row=getrow(cc);
//alert("cc: " + cc);
	for (j=0;j<9;j++) {
		if (board[row_index[row][j]]&allow_bits[num]) {
			board[row_index[row][j]] &= ~allow_bits[num];
			if ((board[row_index[row][j]]&allow_mask)==0) return(0);
		}
	}

	// clear this digit on same column
	var col=getcol(cc);
	for (j=0;j<9;j++) {
		if (board[col_index[col][j]]&allow_bits[num]) {
			board[col_index[col][j]] &= ~allow_bits[num];
			if ((board[col_index[col][j]]&allow_mask)==0) return(0);
		}
	}

	// clear this digit in same box
	var box=getbox(cc);
	for (j=0;j<9;j++) {
		if (board[box_index[box][j]]&allow_bits[num]) {
			board[box_index[box][j]] &= ~allow_bits[num];
			if ((board[box_index[box][j]]&allow_mask)==0) return(0);
		}
	}

	// process all singletons created by setting
	for (i=0;i<81;i++)
		for (d=0;d<9;d++)
			if ((board[i]&allow_mask)==allow_bits[d])
				if (!setallowed(board,i,d)) return(0);

	// check each digit still available in each box, row and column
	if (!boxcheck(board)||!rowcheck(board)||!colcheck(board))
		return(0);

	// process all singletons created by setting (double check)
	for (i=0;i<81;i++)
		for (d=0;d<9;d++)
			if ((board[i]&allow_mask)==allow_bits[d])
				if (!setallowed(board,i,d)) return(0);

	return(1);
}

// check if board is a solution
function chksolved(board)
{
	var i;
	var nchoices=0;

	// count # choices left
	for (i=0;i<81;i++)
		if ((board[i]&allow_mask)!=0)
				nchoices++;

	// solved?
	if (nchoices==0) solved=1;

	// OK
	return(solved);
}

// debug variable to test depth of search
var maxlevel;

// attempt to solve from this situation
function attempt(pboard,level)
{
	var board=new Array(81);
	var i,j,k;
	var s,e;

	// check for runaway
	if (level > maxlevel) {
		maxlevel=level;
		// alert("Level="+level);
	}
	if (level > 25) return;		// probably gone wrong

	// pick starting square at random
	i=s=rand(81);
	do {
	  if ((pboard[i]&allow_mask)!=0) {
		// pick starting digit at random
		j=e=rand(9);
		do {
		  if (pboard[i]&allow_bits[j]) {
			// push current solution
			for (k=0;k<81;k++) board[k]=pboard[k];
			// try out digit
			if (setallowed(board,i,j)) {
				board[i] = (board[i] & ~digit_mask) | j;
				if (chksolved(board)) {
					for (k=0;k<81;k++) pboard[k]=board[k];
					return;
				}
				// recurse
				attempt(board,level+1);
				if (chksolved(board)) {
					for (k=0;k<81;k++) pboard[k]=board[k];
					return;
				}
				// no good
				board[i] |= digit_mask;
				if (level > 2) return;	// don't both searching anymore
			}
		  }
		  j=(j+1)%9;
		} while (j!=e);
	  }
	  i=(i+1)%81;
	} while (i!=s);
}

//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// create a new initial configuration
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
function docreate()
{
	var i,d;

	do {
		// clear the board
		doclear();
		solved=0;
		maxlevel=0;

		// assign one of each digit at random
		for (d=0;d<9;d++) {
			i=rand(81);
			if (board[i]&allow_bits[d]) {
				setallowed(board,i,d);
				board[i] = (board[i] & ~digit_mask) | d;
			}
		}

		// attempt to solve from here
		attempt(board,0);

		// display result
		for (i=0;i<81;i++) {
			if ((0<=(board[i]&digit_mask))&&((board[i]&digit_mask) < 9)) board[i] |= lock_flag;
			setdigit(i,board[i]&digit_mask);
		}

		if (!solved)
			alert("Failed to make puzzle\nTrying again.");

	} while (!solved);

	// display cursor
	ccell=0;
//	var pfield=document.getElementById("c"+ccell);
//	if (board[ccell]&lock_flag)
//		pfield.className="digitlock";
//	else
//		pfield.className="digit";
//	pfield.style.backgroundColor="#eeddcc";
//	pfield.focus();

	// set animation trigger
	animtrigger=1;

	var sSquaresSelected = "";
	var sBoardList = "";
	for (i = 0; i < 81; i++)
	{
		sSquaresSelected += board[i] + ",";
		sBoardList += digit[(board[i]&solve_mask)>>4];		// + ",";
	}
//alert(sBoardList);
	document.frmNewSudoku.SudokuValue.value = sBoardList;
	document.frmNewSudoku.SquareSelected.value = sSquaresSelected;
}

// find a possible move in a board
function findmove(board)
{
	var i,d;
	var s;

	// pick starting square at random
	i=s=rand(81);
	do {
		if (!(board[i]&allow_mask)) {
			d=(board[i]&solve_mask)>>4;
			if ((board[i]&digit_mask)!=d) return(i);
		}
		i=(i+1)%81;
	} while (i!=s);
	// failed
	return(-1);
}

// give a hint
function dohint()
{
	var tboard=new Array(81);
	var i,j,k,l,d;
	var s,t;

	// reset work arrays
	for (i=0;i<81;i++)
		tboard[i]=allow_mask | solve_mask | digit_mask;

	// add in current cells
	s=-1;
	i=t=rand(81);
	do {
		c=board[i] & digit_mask;
		if ((0<=c)&&(c<9)) {
			tboard[i] = (tboard[i] & ~digit_mask) | c;
			if (!setallowed(tboard,i,c)) {
				alert("Starting position impossible, lastchar="+digit[c]);
				return;
			}
			if ((s=findmove(tboard))>=0) {
				if ((board[s]&digit_mask)==digit_mask) break;
			}
		}
		i=(i+1)%81;
	} while (i!=t);

	// find a possible go
	// s=findmove(tboard);

	if (s>=0) {
		cellblink(s);
	}
	else {
//		for (i=0;i<81;i++) {
//			s="";
//			for (j=0;j<9;j++) if (tboard[i]&allow_bits[j]) s=digit[j]+s;
//			if (s!="") {
//				var pfield=document.getElementById("c"+i);
//				pfield.value="("+s+")";
//	Tempboard[i]=("+s+")";
//			}
//		}
		alert("No hint available.");
		cell(ccell);
	}
}

// find and display complete solution
function dosolution(show)
{
	var pboard=new Array(81);
	var	i,c;

	if (show) {

		if (!solved) {
			// reset solution
			for (i=0;i<81;i++) pboard[i] = allow_mask | solve_mask | digit_mask;
			// add in current cells
			for (i=0;i<81;i++) {
				c=board[i] & digit_mask;
				if ((0<=c)&&(c<9)) {
					if (!setallowed(pboard,i,c)) {
						alert("Starting position impossible.\nFailed at cell="+i+" char="+digit[c]);
						return;
					}
				}
			}
			// attempt solution
			attempt(pboard,0);

			// copy solution into main board
			for (i=0;i<81;i++)
				board[i] = (board[i] & ~solve_mask) | (pboard[i] & solve_mask);
		}

		// display solution
		for (i=0;i<81;i++) {
//			var pfield=document.getElementById("c"+i);
//			pfield.value=digit[(board[i]&solve_mask)>>4];
			Tempboard[i]=digit[(board[i]&solve_mask)>>4];
		}
	}
	else {
		// restore board contents
		for (i=0;i<81;i++) {
//			var pfield=document.getElementById("c"+i);
//			pfield.value=digit[board[i]&digit_mask];
			Tempboard[i]=digit[board[i]&digit_mask];
		}
	}
}

// save board to cookie on user's machine
function saveboard()
{
	var s=board.join("|");
	var exp = new Date();
	var oneYearFromNow = exp.getTime() + (365 * 24 * 60 * 60 * 1000);
	exp.setTime(oneYearFromNow);
	document.cookie = "sudoku="+s+"; expires=" + exp.toGMTString();
}

// get a variable from a cookie string
function getCookieData(labelName)
{
	var labelLen = labelName.length;
	var cookieData = document.cookie;
	var cLen = cookieData.length;
	var i = 0;
	var cEnd;
	while (i < cLen) {
		var j = i + labelLen;
		if (cookieData.substring(i,j) == labelName) {
			cEnd = cookieData.indexOf(";",j);
			if (cEnd == -1) {
				cEnd = cookieData.length;
			}
			return unescape(cookieData.substring(j+1, cEnd));
		}
		i++;
	}
	return "";
}

// restore board from cookie on user's machine
function restoreboard()
{
	var s=getCookieData("sudoku");
	var a=s.split("|");
	if (a.length==81) {
		var i;
		for (i=0;i<81;i++) {
			board[i]=a[i];
			setdigit(i,board[i]&digit_mask);
		}
	}
}

// animation state
var state=0;

// animate a pattern of colours
function animate()
{
	var	i,j;
	var	colours=new Array("#ffffcc", "#ffccff","#ccffff","#eeeeee");

	if (state < 81) {
		i=spiral[(state+80)%81];
		j=spiral[state];
//		var pfield=document.getElementById("c"+i);
//		pfield.style.backgroundColor="#eeeeee";
//		var pfield=document.getElementById("c"+j);
//		pfield.style.backgroundColor="#eecccc";
//		var pfield=document.getElementById("c"+(80-i));
//		pfield.style.backgroundColor="#eeeeee";
//		var pfield=document.getElementById("c"+(80-j));
//		pfield.style.backgroundColor="#cceecc";
	}
	else {
		clearInterval(animthread);
		animthread=setInterval("animate()",100);
		for (i=0;i<target0.length;i++) {
			j=target0[i];
//			var pfield=document.getElementById("c"+j);
//			pfield.style.backgroundColor=colours[state%4];
		}
		for (i=0;i<target1.length;i++) {
			j=target1[i];
//			var pfield=document.getElementById("c"+j);
//			pfield.style.backgroundColor=colours[(state+1)%4];
		}
		for (i=0;i<target2.length;i++) {
			j=target2[i];
//			var pfield=document.getElementById("c"+j);
//			pfield.style.backgroundColor=colours[(state+2)%4];
		}
		for (i=0;i<target3.length;i++) {
			j=target3[i];
//			var pfield=document.getElementById("c"+j);
//			pfield.style.backgroundColor=colours[(state+3)%4];
		}
		for (i=0;i<target4.length;i++) {
			j=target4[i];
//			var pfield=document.getElementById("c"+j);
//			pfield.style.backgroundColor=colours[(state+4)%4];
		}
	}

	state = state+1;
}

// cancel animation
function noanimate()
{
	if (animthread) {
		clearInterval(animthread);
		animthread=null;
	}
	for (i=0;i<81;i++) {
//		var pfield=document.getElementById("c"+i);
//		pfield.style.backgroundColor="#eeeeee";
//		pfield.className="digit";
	}
	state=0;
}
// stop hiding -->
