// ** COPYRIGHT (c) 1998, 2006 STEFAN WANER **// ****************** ALL RIGHTS RESERVED *******************this.Name - "fancyMA";// window.onerror = myErrorTrap;var errorFlag = 1 // set it to zero to suppress error message.// var exit = false; // get out of herevar cookiesEnabled = true;var tab = unescape( "%09" );	// these are now the appropriate strings;var cr = unescape( "%0D" );	var lf = unescape( "%0A" );var symb = unescape( "%C5" );var backSlash = unescape( "%5C" );var powerSymbol = unescape("%5E");var quoteMark = unescape( '%22' );var singlequoteMark = unescape( '%27' );var semicolon = unescape( '%3B' );var storedInput = ''; // for undeletingvar storedOutput = '';var storedExpr = '';var theSmallestNumber = 0.000000000001	// everything smaller is set to zero in rowreducevar stackPtr = 0; // not used -- residue from uindo ops in pivotscriptvar operationsStack = new Array();// var powerSymbol = unescape('%26');	// above is amplisand for testingvar comma = ",";var singular = false;var msFormat = false;var Reading = true;var numberActiveMatrices = 0;var numberNamedMatrices = 1;var maxRows = 26;var maxCols = 26;var inputExpression = ""; 	// the expression to evaluate var theOriginalExpr  = '';var numSigDigs = 6;			// default accuracyvar sigDigMode = true;		// significant digits vs decimal places roundingvar maxNumberSteps = 20; 		// maximum depth of an iterationvar maxNumberMatrices = 20;	// maximum number of named matgricesvar bigMatrix = new makeArray3(maxNumberSteps, maxRows,maxCols);var bigMatrix2 = new makeArray3(maxNumberMatrices, maxRows,maxCols);// hide their dimensions in (maxRows,1) and (1, maxCols)// and the name of the matrix in (maxRows, maxCols)// now the identityfor (var i = 1; i <= maxRows-1; i++)	{	for (var j = 1; j <= maxCols-1; j++)		{		if (i == j) bigMatrix2[1][i][j] = 1;		else bigMatrix2[1][i][j] = 0;		} // j	} // ibigMatrix2[1][maxRows][1] = maxRows-1; // default is a 1x1 matrixbigMatrix2[1][1][maxCols] = maxCols-1;bigMatrix2[1][maxRows][maxCols] = "I";// end of defining the identityvar numberActiveMatrices = 0; // the number of iterations in an expressionvar maxDenom = 10000;  // for fraction approximationvar tol = .000000001; // for 10 digit accuracy guaranteed cutoff for fractin approx not yet implementedvar tooBigString = "Too many matrices in your expression," + cr + "or your expression is too complicated." + cr +"Please keep it simple!"var theSaveName = "Matrices";// the Instructionsvar theSampleFormulaString = "Enter the matrices in the large text box above and the" + cr +  "formula you want to evaulate in the formula box." + "\n\r" + "Sample formulas are:" + cr + tab;var sampleExpressions = "Here are some other expressions you can try:";sampleExpressions += cr +tab+ "A*B" + tab + tab + "(product)";sampleExpressions += cr+tab+"A*B" + tab + tab + "(sum)";sampleExpressions += cr+ tab+"A+(B*C)   or   A+B*C";sampleExpressions += cr+ tab+"A - 4*I" + tab + tab + "(I = identity matrix)";sampleExpressions += cr + "NOTE ON IDENTITY: When you include 'I' in the formula, it will automatically" + cr + "use the correct size identity matrix." + cr + "If you want to specify a particular size identity matrix, use another" + cr + "name for it and enter it in the top box."sampleExpressions += cr+ tab+"A^-1" + tab + tab + "(inverse)";sampleExpressions += cr+ tab+"A^2" + tab + tab + "(powers of A)";sampleExpressions += cr+ tab+"reduce(A^2)" + tab + "(row-reduced echelon form of A^2)";sampleExpressions += cr+ tab+"(A+B)^T" + tab + tab + "(transpose of A+B)";sampleExpressions += cr+ tab+"det(A+B)" + tab + "(determinant of A+B)";sampleExpressions += cr + "NOTE ON UPPER CASE: The parser is case sensitive: P is not the same matrix as p."var theSampleMatrixString = "A = [1, -3, 2" + cr + "0, -3, 22/3" + cr + "6, -4, 1 ]" + cr + cr +"B = [-2, -3, 0" + cr + "-1, 3, 6" + cr + "6, -4, 1 ]" + cr + cr + "Let S = (B-I)^-1" + cr + cr + "C = [ 0.25" + cr + "-3.2" + cr + "-4 ]";theSampleMatrixString += cr+cr+"The matrices are defined above using square brackets and commas as shown. "+cr+"Matrix names must be a single letter. I is reserved for the identity matrix. You need not define it."+cr + "To define a new matrix in terms of others higher on the list, use a 'Let' statement as shown above." + cr +"See below for some formula syntax." + cr + "To compute more than one expression, separate them by commas." + cr + "**NEW** You can now also enter matrices using MATLAB notation (semicolons for new rows)" + cr + "as in D = [1,2;3,4;5,6]).";// end instructionsvar zero = new makeArray (1, 0); // a 1x1 zero matrixvar fractionMode = false;var okToRoll = true;var browserName = navigator.appName;var browserVersion = navigator.appVersion;if ( (browserName == "Netscape") && (parseInt(browserVersion) >= 3)) browserName = "N";else if ( (browserName == "Microsoft Internet Explorer") && (parseInt(browserVersion) >= 3) ) browserName = "M";// ****************** ERROR HANDLER *************function myErrorTrap(message,url,linenumber) {if (errorFlag == 1) alert("Sorry, I can't process this. Check the syntax of your input matrices and formulas. Save your matrices and then press 'Example' for general information.");errorFlag = 1;return (true);} // end of on error// ******************COOKIE ROUTINES *****************function setCookie (cookieName, cookieValue, expires, path, domain, secure) {  document.cookie =     escape(cookieName) + '=' + escape(cookieValue)     + (expires ? '; EXPIRES=' + expires.toGMTString() : '')    + (path ? '; PATH=' + path : '')    + (domain ? '; DOMAIN=' + domain : '')    + (secure ? '; SECURE' : '');}function getCookie (cookieName) {  var cookieValue = null;  var posName = document.cookie.indexOf(escape(cookieName) + '=');  if (posName != -1) {    var posValue = posName + (escape(cookieName) + '=').length;    var endPos = document.cookie.indexOf(';', posValue);    if (endPos != -1)      cookieValue = unescape(document.cookie.substring(posValue, endPos));    else      cookieValue = unescape(document.cookie.substring(posValue));  }  return cookieValue;}function verifyList() {// This reconciles the save list with the actual files. // In particular it removes files that have expired.var now = new Date();var nextyear = new Date(now.getTime() + 1000 * 60 * 60 * 24 * 365);var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);var theList = getCookie('saveList');// alert(theList);var theStr = '';var theName = '';if (theList != null) {	var theArray = parser(theList,"$");	var n = theArray[0]-1;// alert(theArray[2]);	if (n <= 0) setCookie('saveList','',yesterday);	else {		for (var i = 1; i <= n; i++) {			theName = theArray[i];			var theData = getCookie(theName);			if (theData != null) {				theStr += theName + '$';				setCookie(theName, theData, nextyear);				// to update old data cookies				} // end if			} // i		if (theStr == '') setCookie('saveList','',yesterday);		else setCookie('saveList',theStr,nextyear);		} // end else	} // end if}// ***************** END OF COOKIE ROUTINES ****************// ******************** MATH UTILITIES ******************function hcf (a,b) {var bigger = Math.abs(a);var smaller = Math.abs(b);var x = 0;var theResult = 1;if ( (a == 0) || (b == 0) ) return(1);if (smaller > bigger) {x = bigger; bigger = smaller;  smaller = x}var testRatio = roundSigDig(bigger/smaller, 11);var testRatio2 = 0;if (testRatio == Math.floor(testRatio) ) return (smaller)else	{	// look for a factor of the smaller, deplete it by that factor and multiply bigger by it	var found = false;	var upperlimit = smaller;	for (var i = upperlimit; i >= 2; i--)		{		testRatio = roundSigDig(smaller/i, 10);		testRatio2 = roundSigDig(bigger/i, 10);		if  ( (testRatio == Math.floor(testRatio) ) && (testRatio2 == Math.floor(testRatio2) ) )			{			smaller = Math.round(smaller/i);			smaller = Math.round(bigger/i);			return(theResult *hcf(bigger, smaller) );			}		}		return(theResult);		}alert("error!");return(-1); // should never get here} // hcf// *** reducing a fraction ***function reduce(fraction){with (Math)	{	var HCF = hcf(fraction[1], fraction[2]);	fraction[1] = Math.round(fraction[1]/HCF);	fraction[2] = Math.round(fraction[2]/HCF);	} // with mathreturn(fraction);} // reduce fractionfunction toFrac(x, maxDenom, tol) {// tolerance is the largest errror you will tolerate before resorting to // expressing the result as the input decimal in fraction form// suggest no less than 10^-10, since we round all to 15 decimal places.	var theFrac = new Array();	theFrac[1] = 0;	theFrac[2] = 0;	var p1 = 1;	var p2 = 0;	var q1 = 0;		var q2 = 1;		var u =0;	var t = 0;	var flag = true;	var negflag = false;	var a = 0;	var xIn = x; // variable for later	if (x >10000000000) return(theFrac);while (flag)	{	if (x<0) {x = -x; negflag = true; p1 = -p1}	var intPart = Math.floor(x);	var decimalPart = roundSigDig((x - intPart),15);	x = decimalPart;	a = intPart;		t = a*p1 + p2;	u = a*q1 + q2;	if  ( (Math.abs(t) > 10000000000 ) || (u > maxDenom ) ) 		{			n = p1;			d = q1;			break;		}		p = t;		q = u;			//		cout << "cf coeff: " << a << endl; // for debugging//		cout << p << "/" << q << endl;	// for debugging			if ( x == 0 )		{		n = p;		d = q;		break;		}		p2 = p1;		p1 = p;		q2 = q1;		q1 = q;		x = 1/x;		} // while ( true );		theFrac[1] = n;	theFrac[2] = d;	if (theFrac[2] == 1) return (theFrac[1].toString());	else return (theFrac[1] + "/" + theFrac[2]);} // toFracfunction roundSix(theNumber) {var x = (Math.round(1000000*theNumber))/1000000;return(x);}function shiftRight(theNumber, k) {	if (k == 0) return (theNumber)	else		{		var k2 = 1;		var num = k;		if (num < 0) num = -num;		for (var i = 1; i <= num; i++)			{			k2 = k2*10			}		}	if (k>0) 		{return(k2*theNumber)}	else 		{return(theNumber/k2)}	}function roundSigDig(theNumber, numDigits) {	with (Math)		{				if (theNumber == 0) return(0);		else if(abs(theNumber) < 0.000000000001) return(0);// WARNING: ignores numbers less than 10^(-12)		else			{			var k = floor(log(abs(theNumber))/log(10))-numDigits+1			var k2 = shiftRight(round(shiftRight(abs(theNumber),-k)),k)			if (theNumber > 0) return(k2);			else return(-k2)			} // end else		}	}function roundDec(theNumber, numPlaces) {	with (Math)		{		var x =shiftRight(round(shiftRight(theNumber,numPlaces)),-numPlaces);		return x;		} // with math} // roundDecfunction looksLikeANumber(theString) {// returns true if theString looks like it can be evaluatedvar result = true;var length = theString.length;var x = ""var y = "1234567890-+^*./ "var yLength = y.length;for (var i = 0; i <= length; i++)	{ 	x = theString.charAt(i);		result = false;		for (var j = 0; j <= yLength; j++) 			{			if (x == y.charAt(j)) {result = true; break}			} // j	if (result == false) return(false);	} // ireturn(result);} // looks like a numberfunction isCharHere (InString, RefString)  {	if(InString.length!=1) 		return (false);	if (RefString.indexOf (InString, 0)==-1) 		return (false);	return (true);}function insertParenAfter(InString, theChar, theSymbolsToEnclose)  {// insert open paren after theChar// and closes it after the string of symbols (eg a number)// needs checkstring// does not insert anything if paren already there var outString = "";var tempChar = "";var stringLength = InString.length;if (InString == "") outString = InString;else 	{	for (var i = 0; i <= InString.length; i++)		{		tempChar = InString.charAt(i);		if ((tempChar == theChar) && (InString.charAt(i+1) != unescape ('%28')))			{			outString += tempChar + unescape ('%28')  			for (var j = 1; j <= stringLength - i; j++)				{				var digit = InString.charAt(i+j);				if (!isCharHere(digit, theSymbolsToEnclose) || i+j == stringLength )					{					// now close parens and advance i					outString += unescape ('%29');					i += j;					j = stringLength;					} // if				outString += digit;				} // j			}		else outString += tempChar;		} // i	}return(outString);} // insertParenAfterfunction checkString(InString,subString,backtrack)// check for subString// if backtrack = false, returns -1 if not found, and left-most location in string if found// if backtrack = true, returns -1 if not found, and right-most location in string if found// note that location is to the left of the substring in both cases{var found = -1;var theString = InString;var Length = theString.length;var symbLength = subString.length;for (var i = Length- symbLength; i >-1; i--)	{		TempChar=theString.substring (i, i+ symbLength);	if (TempChar == subString) 			{			found = i;			if (backtrack) i = -1			}	} // ireturn(found);} // checkfunction parser (InString, Sep)  {	NumSeps=1;	for (Count=1; Count < InString.length; Count++)  {		if (InString.charAt(Count)==Sep)			NumSeps++;	}	parse = new makeArray (NumSeps);	Start=0; Count=1; ParseMark=0;	LoopCtrl=1;	while (LoopCtrl==1)  {		ParseMark = InString.indexOf(Sep, ParseMark);		TestMark=ParseMark+0;		if ((TestMark==0) || (TestMark==-1)){			parse[Count]= InString.substring (Start, InString.length);			LoopCtrl=0;			break;		}		parse[Count] = InString.substring (Start, ParseMark);		Start=ParseMark+1;		ParseMark=Start;		Count++;	}	parse[0]=Count;	return (parse);}function evaluate(theString) {if (browserName == "N") return(Math.eval(theString));else	{	var theValue = 0;	var Ret = parser(theString,"/");	if (Ret[0] == 1) theValue = parseFloat(theString);	else theValue = parseFloat(Ret[1])/parseFloat(Ret[2]);	return (theValue);	}}function replaceChar (InString,oldSymbol,newSymbol)  {	var OutString="";	var TempChar = "";	for (Count=0; Count < InString.length; Count++)  {		TempChar=InString.substring (Count, Count+1);		if (TempChar!=oldSymbol)			OutString=OutString+TempChar		else OutString=OutString+newSymbol;	}	return (OutString);}function replaceSubstring (InString,oldSubstring,newSubstring)  {	OutString="";	var sublength = oldSubstring.length;	for (Count=0; Count < InString.length; Count++)  {		TempStr=InString.substring (Count, Count+sublength);		TempChar=InString.substring (Count, Count+1);		if (TempStr!= oldSubstring)			OutString=OutString+TempChar		else 			{			OutString=OutString+ newSubstring;			Count +=sublength-1			}	}	return (OutString);}function rightString(InString, num)  {	var OutString=InString.substring (InString.length-num, InString.length);	return (OutString);}function rightStringFrom(InString, num)  {	var OutString=InString.substring (num, InString.length);	return (OutString);}function leftString(InString, num)  {	var OutString=InString.substring (0, num);	return (OutString);}function findParenmatch(InString,beginMark,parentype,backtrack) {// parentype is (  or [  or {  open only allowed// returns an array X[0] = -1 if none found, 1 if found// X[1] = position of first char inside paren// X[2] = position of last char inside paren// X[3] = string insidevar X = new makeArray(4,0);var theString = "";if (backtrack) theString = InString.substring(0,beginMark);else theString = InString.substring(beginMark,InString.length);// alert (theString);var Length = theString.length;if (Length < 2) {X[0] = -1; return(X)}var count = 0; var parenclose = ")";if (parentype == "{") parenclose = "}";else if (parentype == "[") parenclose = "]";if (!backtrack)	{	var start = checkString(theString,parentype,backtrack);	if (start == -1) {X[0] = -1; return(X)}	X[1] = beginMark + start+1; // start of inside	var parencount = 1;// alert(start+1);	for (var i = start+1; i <= Length; i++)		{		var tempChar = theString.charAt(i);		if (tempChar == parentype) parencount++;		else if (tempChar == parenclose) parencount--;		if (parencount == 0) 			{			X[0] = 1;			X[2] = beginMark + i; 	// just before -- at -- the last char			X[3] = theString.substring(start+1,i);			return(X);			}		} // i	} // if !backtrackelse	{	var end = checkString(theString, parenclose,backtrack);	if (end == -1) {X[0] = -1; return(X)}	X[2] = end; //end of inside	var parencount = 1;	for (var i = end-1; i >=0; i--)		{		var tempChar = theString.charAt(i);		if (tempChar == parentype) parencount--;		else if (tempChar == parenclose) parencount++;		if (parencount == 0) 			{			X[0] = 1;			X[1] = i+1; 	// just before -- at -- the last char			X[3] = theString.substring(X[1],X[2]);			return(X);			}		} // i	} // if backtrackreturn(X);}// end findParenmatchfunction parseOuterParen(InString, beginMark, parentype, backtrack) {// returns location, left tail, right tail, and inside of a outermost matched parenthesis starting at any point// parentype is "("  or "["  or "{"// returns an array X[0] = -1 if none found, 1 if found// X[1] = position of first char inside paren// X[2] = position of last char inside paren// X[3] = string inside// X[4] = left tail of string outside closed paren// X[5] = right tail of string outside closed parenvar X = new makeArray(4,0);var L = InString.length;var theString = "";if (backtrack) theString = InString.substring(0,beginMark);else theString = InString.substring(beginMark,L);// alert (theString);var Length = theString.length;if (Length < 2) {X[0] = -1; return(X)}var count = 0; var parenclose = ")";if (parentype == "{") parenclose = "}";else if (parentype == "[") parenclose = "]";if (!backtrack)	{	var start = checkString(theString,parentype,backtrack);	if (start == -1) {X[0] = -1; return(X)}	X[1] = beginMark + start+1; // start of inside	var parencount = 1;// alert(start+1);	for (var i = start+1; i <= Length; i++)		{		var tempChar = theString.charAt(i);		if (tempChar == parentype) parencount++;		else if (tempChar == parenclose) parencount--;		if (parencount == 0) 			{			X[0] = 1;			X[2] = beginMark + i; 	// just before -- at -- the last char			X[3] = theString.substring(start+1,i);			X[4] = InString.substring(0,X[1]-1);			X[5] = theString.substring(X[2]-beginMark+1, Length);// alert(X[4] + "{INSIDE IS***" + X[3] + "***}" + X[5]);			return(X);			}		} // i	} // if !backtrackelse	{	var end = checkString(theString, parenclose,backtrack);	if (end == -1) {X[0] = -1; return(X)}	X[2] = end; //end of inside	var parencount = 1;	for (var i = end-1; i >=0; i--)		{		var tempChar = theString.charAt(i);		if (tempChar == parentype) parencount--;		else if (tempChar == parenclose) parencount++;		if (parencount == 0) 			{			X[0] = 1;			X[1] = i+1; 	// just before -- at -- the last char			X[3] = theString.substring(X[1],X[2]);			X[4] = theString.substring(0,X[1]-1);			X[5] = InString.substring(X[2]+1, L);// alert(X[4] + "{***}" + X[5]);			return(X);			}		} // i	} // if backtrackreturn(X);}// end parseOUterParen// ******************** FORM UTILITIES ******************function sesame(url,hsize,vsize){ // Default size is 550 x 400        var tb="toolbar=0,directories=0,status=0,menubar=0"        tb+=",scrollbars=1,resizable=1,"    var tbend="width="+hsize+",height="+vsize;    if(tbend.indexOf("<undefined>")!=-1){tbend="width=550,height=400"}      tb+=tbend     	Win_1 = window.open("","win1",tb);      Win_1 = window.open(url,"win1",tb); 	Win_1.focus();    }function readSpreadsheet() {// ******************************************// matrixName is the name of the matrix you want to find.// finds and stores the matrix of that name// returns a warning if not// in Version 2.0 also computes "Let" type formlas// ******************************************// first put in some crs because the program likes them // double cr's will be gotten rid of later... Reading = true;var theString = document.theSpreadsheet.input.value; theString = stripSpaces(theString);theString = replaceChar(theString,semicolon,cr);	// to handle MATLAB notationtheString = replaceChar(theString,lf,cr);	// get rid of those nasty line-feeds theString = replaceSubstring(theString,"[", cr+"["+cr);theString = replaceSubstring(theString,"]", cr+"]"+cr);// now for some additional flexibility in formattingtheString = replaceSubstring(theString, ","+cr,cr); // for accidental commas at end of a line// Let statements nowtheString = replaceSubstring(theString, "Let","let");theString = replaceSubstring(theString, "LET","let");theString = replaceSubstring(theString, "LEt","let");// *** testing *******// document.theSpreadsheet.output.value = theSampleMatrixString;// document.theSpreadsheet.output.value +=  "\r" +  checkString(theString, cr+cr,false);// var matrixName = "A";// *** testing *******//  alert ("here");// now get rid of strings of more than one tab and one cr's in a rowvar doubletab = true; var doublecr = true;while ( (doubletab) || (doublecr) )	{	if (checkString(theString,tab+tab,false) == -1) doubletab = false;	else theString = replaceSubstring(theString,tab+tab,tab);	if (checkString(theString,cr+cr,false) == -1) doublecr = false;	else theString = replaceSubstring(theString,cr+cr,cr);	}theString = replaceSubstring(theString,"="+cr,"="); // prefer "=["theString = replaceSubstring(theString,tab+cr,cr); // get rid of tab + crs // get the names of the matrices;var tempAr = parser(theString,"=");	if (tempAr[0] == -1) { return (0)}// *********ERROR TRAP TO TAKE CARE OFvar numMatrices = tempAr[0]-1;// alert ("numMatrices = " + numMatrices);for (var v = 1; v <= numMatrices; v++)	{	// ERROR TRAP FOR TOO MANY HERE	tempAr[v] = stripSpaces(tempAr[v]);	var l = tempAr[v].length;	var tempstr = tempAr[v].substring(l-1,l)	var matrixName = tempstr;// alert(numberNamedMatrices);// First check to see if we have a Let statement// alert(tempAr[v]);	var letPos = checkString(theString,"let"+matrixName,false);	if (letPos > -1) {// alert(numberNamedMatrices);		// first store the value of numberActiveMatrices		// as this gets messed up by extract and process		// restore it at the end of this 				// Now look for the next carriage return		var length = theString.length;		var theRest = theString.substring(letPos, length);// alert(theRest);		var crPos = checkString(theRest,cr,false); // alert(crPos);		if (crPos == -1) crPos = length;		var theSegment = theString.substring(letPos+5,letPos + crPos);		// position of rightmost cr// alert("Let string = "+theSegment); 		// now put all the named matrix data thusfar into bigMatrix		// for processing		numberActiveMatrices = numberNamedMatrices;		for (var i = 1; i <= numberNamedMatrices; i++) {			bigMatrix[i] = bigMatrix2[i]// alert(i + ", " + bigMatrix2[i][maxRows][maxCols]);			}		numberNamedMatrices += 1;		theExpression = preProcess(theSegment);// alert(theExpression);		extractAndProcess(theExpression);// alert(" let matrixName " + matrixName);		// now restore numberactive matrices;		// at this point we need to create the new matrix defined by the let statement		var checkdig = lookup2(matrixName);// if ((numberNamedMatrices == 5)|| (numberNamedMatrices == 4)) alert(bigMatrix2[4][maxRows][maxCols]); // alert(bigMatrix2[4][maxRows][maxCols]);		if (checkdig == -1) { 						for (var i = 1; i <= maxRows; i++) {				for (var j = 1; j <= maxCols; j++) {					bigMatrix2[numberNamedMatrices][i][j] = bigMatrix[numberActiveMatrices][i][j];				}			}			bigMatrix2[numberNamedMatrices][maxRows][maxCols] = matrixName;			// alert("Just created new Let Matrix Called " + bigMatrix2[numberNamedMatrices][maxRows][maxCols]+ " and matrix number " + numberNamedMatrices);// alert(bigMatrix2[3][1][1]);			}		else {			for (var i = 1; i <= maxRows; i++) {				for (var j = 1; j <= maxCols; j++) {					bigMatrix2[checkdig][i][j] = bigMatrix[numberActiveMatrices][i][j];				}			}				bigMatrix2[checkdig][maxRows][maxCols] = matrixName;// alert("Just repalaced Matrix Called " + matrixName + " and matrix number " + checkdig);			}for (var i = 1; i <= numberNamedMatrices; i++) {// alert(i + ", " + bigMatrix2[i][maxRows][maxCols] + " " + bigMatrix2[i][1][1]);}// this replaces an old matrix by a newly defined one to avoid multiple copies of matrices with the same namefor (var i = 1; i <= numberNamedMatrices; i++) {		bigMatrix[i] = bigMatrix2[i];	}numberActiveMatrices = numberNamedMatrices;		} // end of processing Let statements	else {for (var i = 1; i <= numberNamedMatrices; i++) {// alert(i + ", " + bigMatrix2[i][maxRows][maxCols]);}		var tempString = matrixName + "=[";		var X = checkString(theString,tempString,false);		// X is the position of the start of the matrix		if (X == -1) {okToRoll = false; document.theSpreadsheet.output.value = "You have not properly entered a matrix with the name " + matrixName + "." + "\r" + theSampleMatrixString; return(zero)}		if (numberNamedMatrices > maxNumberMatrices)  {document.theSpreadsheet.output.value = tooBigString; return(zero)}		X += 2;  // add on the = sign and the "["		// Now get the substring between the braces// *** testing *******// document.theSpreadsheet.output.value +="X = " + X + "theString = " + theString;// alert ("pausing");// *** testing *******		var endMatrix = -1;		var startMatrix = X+2;		var length = theString.length;		for (var i = X; i <= length; i++)			{				TempChar=theString.substring (i, i+ 1);			if  (TempChar == "]")				{				endMatrix = i;				break;				}			} // i		if (endMatrix <= startMatrix) {okToRoll = false; document.theSpreadsheet.output.value  +=" Either you have not a right bracket at the end of the matrix  "+matrixName + ", \r" + "or the matrtix has no entries."; return(zero)}		var theMatrixString = theString.substring(startMatrix,endMatrix);// alert("here");// *** testing *******// document.theSpreadsheet.output.value += "\r  ***" + theMatrixString + "***";// alert("Pausing");// *** testing *******		// Now search for tabs and returns		var rowArray = parser(theMatrixString,cr);		var numRows = rowArray[0]-1; 		// note that the zero entry is 1 + the nmber of occurrences		// too many rows?		if (numRows > maxRows-1) {document.theSpreadsheet.output.value = "Too many rows in the matrix " + matrixName + "." + cr + "Please limit the number of rows to " + maxRows-1 + "or fewer."; return(zero)}		// now replace all crs and tabls by commas since we know the # of rows		theMatrixString = replaceSubstring(theMatrixString,tab,",");		theMatrixString = replaceSubstring(theMatrixString,cr,",");		var entryArray = parser(theMatrixString,",");		var numCols = (entryArray[0]-1)/numRows;		// too many columns?		if (numCols > maxCols-1) {document.theSpreadsheet.output.value = "Too many columns in the matrix " + matrixName + "." + cr + "Please limit the number of columns to " + maxCols-1 + "or fewer."; return(zero)}// *** testing *******// document.theSpreadsheet.output.value += "\r" +  "numRows = " + numRows+ "numCols = " + numCols;// document.theSpreadsheet.output.value += "\r" + theMatrixString;// alert("Pausing");// *** testing *******// alert ("about to create a new matrix called$$$" + matrixName + "$$$ matrix number = " + numberNamedMatrices);// if (matrixName == "I") alert("creating I");		var checkdig = lookup2(matrixName)		if (checkdig == -1) {			numberNamedMatrices += 1;			createNewMatrixData(theMatrixString,numRows,numCols, numberNamedMatrices,matrixName)}		else createNewMatrixData(theMatrixString,numRows,numCols, checkdig,matrixName); // this replaces an old matrix by a newly defined one to avoid multiple copies of matrices with the same name		} // if not a let statement	} // v (the big loop)for (var i = 1; i <= numberNamedMatrices; i++) {// alert(i + ", " + bigMatrix2[i][maxRows][maxCols]);}Reading = false;return(zero);} // read spreadsheetfunction createNewMatrixData(theString,numRows, numCols,numberMatrix,matrixName) {// ****************Turns a string with commas seperating the elements into// *************** a matrix level of bigMatrix// alert ("here");var tempMatrix = new makeArray2(maxRows,maxCols);var entryArray = parser(theString,",");var k = 1; // first entry in the above arrayfor (i = 1; i <= numRows; i++)	{	for (j = 1; j <= numCols; j++)		{// alert(entryArray[k]);		tempMatrix[i][j] = eval(entryArray[k]);		k++;		} // j	} // itempMatrix[maxRows][1] = numRows;tempMatrix[1][maxCols] = numCols;tempMatrix[maxRows][maxCols] = matrixName;// This still works for Let statements//alert(bigMatrix2[4][maxRows][maxCols]);bigMatrix2[numberMatrix] = tempMatrix;//alert("Just created Matrix2 Called " + matrixName + " and matrix number " + numberMatrix);//alert(bigMatrix2[4][maxRows][maxCols]);// *** testing starts *******// var display = "\r";// for (i = 1; i <= numRows; i++)//	{//	for (j = 1; j <= numCols; j++)//		{//		display += tempMatrix[i][j]  + tab;//		} // j//	display += cr;//	} // i// document.theSpreadsheet.output.value += display;// alert("Pausing");// *** testing *******return(0);} // createNewMatrix// ******************* PARSER FOLLOWS  **************************function preProcess(InString) {var theString = InString; singular = false; // reset singular// ********** Binary Operators *************// first put some parentheses around exponents to fix a curious bug// we allow T in exponent as well  // first adjust for negative powers by substituting first// alert(theString);theString = replaceSubstring(theString,powerSymbol+'T', '#T');  // transposetheString = replaceSubstring(theString,powerSymbol+'t', '#T');theString = replaceSubstring(theString,powerSymbol+'-', powerSymbol+'$');theString = insertParenAfter(theString, powerSymbol, '$0123456789T')theString = replaceChar(theString,'$', '-');// now turn reduce and determinant ops into exponents for easier handling// first reducevar parsingExpression = true;while(parsingExpression) {	parsingExpression = false;	var ch = checkString(theString.toLowerCase(),"reduce",false);	if (ch > -1) { 		var len = theString.length;		parsingExpression = true;		var XR = findParenmatch(theString,ch,"(",false);		var theStr = theString.substring(0, ch) + "(" + XR[3] + ")" + "!R" + theString.substring(XR[2]+1,len);		theString = theStr;		} // if ch found reduce// alert(theString);	}// end of while parsing// determinantvar parsingExpression = true;while(parsingExpression) {	parsingExpression = false;	var ch = checkString(theString.toLowerCase(),"det",false);	if (ch > -1) { 		var len = theString.length;		parsingExpression = true;		var XR = findParenmatch(theString,ch,"(",false);		var theStr = theString.substring(0, ch) + "(" + XR[3] + ")" + "&D" + theString.substring(XR[2]+1,len);		theString = theStr;		} // if ch found det// alert(theString);	}// end of while parsing// alert(theString);var maxExpressionLength = 50;var posn = new makeArray(maxExpressionLength); // position of a binary operatorvar oper = new makeArray(4);for (var i = 1; i <= maxExpressionLength; i++) posn[i] = -1;oper[1] = powerSymbol; oper[2] = "#";oper[3] = "!"; oper[4] = "&";oper[5] = "*";oper[6] = "-";oper[7] = "+";var numOperations = 7;for (i = 1; i <= numOperations; i++) 	{	theString = replaceSubstring(theString,oper[i],symb+oper[i]);	}// will remove the extra symbol when processed// alert(theString);for (i = 1; i <= numOperations; i++)	{ 	posn[i] = checkString(theString,symb+oper[i],false);	var count = 0;	while ( (posn[i] != -1) && (count < 300) )		{		count ++;// alert (theString);		theString = processInfix(theString,oper[i], posn[i]);// alert (theString);		posn[i] = checkString(theString, symb+oper[i], false);		} // while posn[i]... 	} // for i = ...// alert(theString);return (theString);} // end of preprocess // ******************* END PREPROCESSfunction rowReduce(theMatrix,numRows,numCols) {// alert(theMatrix[1][4]);var theNum;for (var i = 1; i <= numRows; i++)	{ 	var theCol = 0;	// search for the leading entry in the ith row	for (var j = 1; j <= numCols; j++)		{		theNum = theMatrix[i][j];		if (Math.abs(theNum) < theSmallestNumber) theMatrix[i][j] = 0;		else {theCol = j; break}		} // j	if (theCol != 0) {theMatrix = pivot(theMatrix,numRows,numCols,i,theCol)}// alert(numRows + " " + numCols);	} // i// alert(theMatrix[1][4]);// Now arrange the pivoted rows by leading entries// search the columns from leftvar theRow = 1;for (j = 1; j <= numCols; j++)	{	for (i = theRow; i <= numRows; i++)		{		if( theMatrix[i][j] != 0) 			{			if (i == theRow) {theRow++; break;}			else { theMatrix = swapRows(theMatrix, numRows, numCols, theRow,i); theRow++; break}			} // found non-zero		} // i	} // j// alert(theMatrix[2][4]);return(theMatrix);} // rowReduce// ***********END ROW REDUCE ***************// *******************PIVOT **********************function pivot(InMatrix,rows,cols,theRow,theCol) {// alert("theRow = " + theRow + "theCol" + theCol);// alert(InMatrix[1][4]);var thePivot = InMatrix[theRow][theCol];for (var i = 1; i <= cols; i++)	{	InMatrix[theRow][i] = InMatrix[theRow][i]/thePivot;	} // i	// now pivotvar theNum = 1;for (var i = 1; i <= rows; i++)	{	if ( (i != theRow) && (InMatrix[i][theCol] != 0) )		{		var factr = InMatrix[i][theCol];		for (var j = 1; j <= cols; j++)			{ // if ((i == 2) && (j == 4)) alert(InMatrix[i][j]);			InMatrix[i][j] = InMatrix[i][j] - factr*InMatrix[theRow][j];// if ((i == 2) && (j == 4)) alert("after the rowop" + InMatrix[i][j]);			} // j					}	} // i// alert(InMatrix[2][4]);return(InMatrix);}// ***************** END PIVOT *********************// ***********SWAP ROWS *************************function swapRows(InMatrix,numRows,numCols,p,q) {var rowHold =0;for(var j = 1; j <= numCols; j++)	{	rowHold = InMatrix[p][j];	InMatrix[p][j] = InMatrix[q][j];	InMatrix[q][j] = rowHold;	} // jreturn(InMatrix);} // end swap rows// ********END SWAP ROWS ************************function processInfix(InString, operation, position) {// position is one before the operation  ... symb*var leftPart = InString.substring(0,position);var Length = InString.length;// alert(leftPart);var rightPart = InString.substring(position+2,Length);// now watch out for numbers added or negative exponents// remove the symbols from these without doing anythingvar theOp = InString.charAt(position+1);if (theOp == "-")	{	var theExpr = rightPart.charAt(0);	if (looksLikeANumber(theExpr) && (leftPart.charAt(position) == "(") ) 		{// alert(leftPart + theOp + rightPart);		return(leftPart + theOp + rightPart);}	}else 	{	var theExpr = leftPart.charAt(position)+ "+" + rightPart.charAt(0);	if (looksLikeANumber(theExpr)) 		{// alert(leftPart + theOp + rightPart); 		return(leftPart + theOp + rightPart);}	}// now scan leftward until another cent sign or beginning of the stringvar backMark = position; var parencount = 0;var putParen = false;for (var i = position-1; i >-1; i--)	{	var theChar = leftPart.charAt(i);// alert(theChar);	if (theChar == ")") parencount++;	else if (theChar == "(") parencount--;		if ( (parencount <= 0) &&(  (theChar == symb) || ( i == 0) || (parencount < 0) ) )	// looks like a place for a left paren		{		if (theChar == symb)  backMark = i+2;		else backMark = i;// alert("i = "+i);		break;		}	} // i// now to the rightvar foreMark = 0;var rLength = rightPart.length; 	var parencount = 0;for (var i = 0; i <= rLength; i++)	{	var theChar = rightPart.charAt(i);	if (theChar == "(") parencount++;	else if (theChar == ")") parencount--;	if ( (parencount <= 0) && ( (theChar == symb) || (i == rLength) || (parencount < 0) ) )	// looks like a place for a right paren		{		if (theChar == symb) foreMark = i;		else foreMark = i+1;		break;		}				} // i// alert("backMark = " + backMark);// alert("foreMark = " + foreMark);var leftString = leftPart.substring(backMark,position);var rightString = rightPart.substring(0,foreMark);		var theString = leftPart.substring(0,backMark) + "(" + leftString + operation + rightString + ")" + rightPart.substring(foreMark,rLength);	// alert(theString);return (theString);}function extractAndProcess(InString){ // if (exit) return("");// alert ("here");// extract innermost operation (---) and sends it off for Processing// alert(InString); var looking = true;theString = InString;var test = lookup(theString);// alert(theString);// alert(lookup2(theString));if (test != -1)	{// alert("***HERE*** Name = " + theString + " Matrix Number = " + test); numberActiveMatrices = test; Process(theString,true); return ("")}var Length = theString.length;var theExpression = "";var startExpression = checkString(theString,"(",true);// alert (startExpression);// if no parentheses, only one stepif (startExpression == -1) 	{// alert ("here"); 	theExpression = theString;	var test = lookup(theExpression);if (test != -1)	{ okToRoll = false;	alert("You have not entered a matrix called "+ theExpression +". The program will probably terminate now.")	}	else Process(theString,true); 	return ("");	}var mark = startExpression + 1;var parenCount = 1;while  ( (mark < Length) && (parenCount > 0) )	{	TempChar=theString.substring (mark, mark+1);	if (TempChar == "(") parenCount++;	else if (TempChar == ")") parenCount--;	mark++;	}if (parenCount == 0) theExpression = theString.substring(startExpression+1,mark-1);else {document.theSpreadsheet.output.value = "There is a syntax error in your expression!"+ cr + "(Unmatched parentheses)"; return('')};var leftString = theString.substring(0, startExpression);var rightString = theString.substring(mark, Length);// alert("we are about to process the expression" + theExpression);var midString = Process(theExpression,false); // alert ("we are reprocessing the String "+ leftString+midString+rightString);extractAndProcess(leftString+midString+rightString);return ("");} // Process and extractfunction Process(theExpression,lastStep) {// alert("In process");// *** here the work is doneif (singular) lastStep = true;var posnExp = checkString(theExpression, powerSymbol, false);var posnTranspose = checkString(theExpression, "#", false);var posnTimes = checkString(theExpression,"*",false);var posnPlus = checkString(theExpression,"+",false);var posnMinus = checkString(theExpression,"-",false);var posnReduce = checkString(theExpression, "!", false);var posnDet = checkString(theExpression, "&", false);if (looksLikeANumber(theExpression)) return (eval(theExpression));else if ( (lastStep == false) &&  (posnExp == -1) && (posnTimes == -1) && (posnPlus == -1) && (posnMinus == -1) && (posnTranspose == -1) && (posnReduce == -1) && (posnDet == -1) ) return (theExpression);else if (posnTranspose > -1) 	{	numberActiveMatrices += 1;// alert ("numberActiveMatrices = " + numberActiveMatrices);	// too many steps?	if (numberActiveMatrices > maxNumberSteps) {document.theSpreadsheet.output.value = tooBigString; return("")}		// now do the work...	theExpression = stripSpaces(theExpression);	var leftMatrix = lookup(theExpression.substring(0, posnTranspose));if (leftMatrix == -1) alert("You have not entered a matrix called " + theExpression + "." + cr + "You will probably get an error message now.");// alert("The matrix looked up is called " + theExpression.substring(0, posnTranspose) );// alert("leftMatrix number = " + leftMatrix);	var leftRowNum = bigMatrix[leftMatrix][maxRows][1];	var leftColNum = bigMatrix[leftMatrix][1][maxCols];	var tempMatrix = new makeArray2(leftColNum, leftRowNum); // Note the reversal	for (var i = 1; i <= leftColNum; i++)		{		for (j = 1; j <= leftRowNum; j++) tempMatrix[i][j] = bigMatrix[leftMatrix][j][i]; // transpose		} // i	// fix up bigMatrix by adding new data	for (var i = 1; i <= leftColNum; i++)		{		for (j = 1; j <= leftRowNum; j++) bigMatrix[numberActiveMatrices][i][j] = tempMatrix[i][j]		} // i	bigMatrix[numberActiveMatrices][maxRows][1] = leftColNum;	bigMatrix[numberActiveMatrices][1][maxCols] = leftRowNum;	bigMatrix[numberActiveMatrices][maxRows][maxCols] = "TEMP"+ numberActiveMatrices;			} // end of transposeelse if (posnReduce > -1) 	{	numberActiveMatrices += 1;// alert ("numberActiveMatrices = " + numberActiveMatrices);	// too many steps?	if (numberActiveMatrices > maxNumberSteps) {document.theSpreadsheet.output.value = tooBigString; return("")}		// now do the work...	theExpression = stripSpaces(theExpression);	var leftMatrix = lookup(theExpression.substring(0, posnReduce));if (leftMatrix == -1) alert("You have not entered a matrix called " + theExpression + "." + cr + "You will probably get an error message now.");// alert("The matrix looked up is called " + theExpression.substring(0, posnTranspose) );// alert("leftMatrix number = " + leftMatrix);	var leftRowNum = bigMatrix[leftMatrix][maxRows][1];	var leftColNum = bigMatrix[leftMatrix][1][maxCols];	var tempMatrix = new makeArray2(leftRowNum, leftColNum); 	for (var i = 1; i <= leftRowNum; i++)		{		for (j = 1; j <= leftColNum; j++) tempMatrix[i][j] = bigMatrix[leftMatrix][i][j]; 		} // i// alert(leftRowNum + " " + leftColNum);// alert(tempMatrix[2][3]);	var tempMatrix2 = rowReduce(tempMatrix,leftRowNum,leftColNum);// alert(tempMatrix2[2][4]);	// fix up bigMatrix by adding new data	for (var i = 1; i <= leftRowNum; i++)		{		for (j = 1; j <= leftColNum; j++) bigMatrix[numberActiveMatrices][i][j] = tempMatrix2[i][j]		} // i	bigMatrix[numberActiveMatrices][maxRows][1] = leftRowNum;	bigMatrix[numberActiveMatrices][1][maxCols] = leftColNum;	bigMatrix[numberActiveMatrices][maxRows][maxCols] = "TEMP"+ numberActiveMatrices;// alert("here");	} // end of reduceelse if (posnDet > -1) 	{	numberActiveMatrices += 1;// alert ("numberActiveMatrices = " + numberActiveMatrices);	// too many steps?	if (numberActiveMatrices > maxNumberSteps) {document.theSpreadsheet.output.value = tooBigString; return("")}		// now do the work...	theExpression = stripSpaces(theExpression);	var leftMatrix = lookup(theExpression.substring(0, posnDet));if (leftMatrix == -1) alert("You have not entered a matrix called " + theExpression + "." + cr + "You will probably get an error message now.");// alert("The matrix looked up is called " + theExpression.substring(0, posnTranspose) );// alert("leftMatrix number = " + leftMatrix);	var leftRowNum = bigMatrix[leftMatrix][maxRows][1];	var leftColNum = bigMatrix[leftMatrix][1][maxCols];	if (leftRowNum != leftColNum) {alert("In the expression " + theOriginalExpr + "you are asking for the determinant of a non-square matrix. You will probably get an error message now."); okToRoll = false};	var tempMatrix = new makeArray2(leftRowNum, leftColNum); 	for (var i = 1; i <= leftRowNum; i++)		{		for (j = 1; j <= leftColNum; j++) tempMatrix[i][j] = bigMatrix[leftMatrix][i][j]; 		} // i// alert(tempMatrix[1][1]);	var theDeterminant = det(tempMatrix);// alert(theDeterminant);	// fix up bigMatrix by adding new data	for (var i = 1; i <= maxRows-1; i++)		{		for (j = 1; j <= maxCols-1; j++) {			if (i == j) bigMatrix[numberActiveMatrices][i][j] = theDeterminant;			else bigMatrix[numberActiveMatrices][i][j] = 0			} // j		} // i	bigMatrix[numberActiveMatrices][maxRows][1] = maxRows-1;	bigMatrix[numberActiveMatrices][1][maxCols] = maxCols-1;	bigMatrix[numberActiveMatrices][maxRows][maxCols] = "$DET"+ numberActiveMatrices;// alert("here");	} // end of reduceelse if (posnExp > -1) 	{	numberActiveMatrices += 1;// alert ("numberActiveMatrices = " + numberActiveMatrices);	// too many steps?	if (numberActiveMatrices > maxNumberSteps) {document.theSpreadsheet.output.value = tooBigString; return("")}		// now do the work...	theExpression = stripSpaces(theExpression);	var leftMatrix = lookup(theExpression.substring(0,posnExp));if (leftMatrix == -1) alert("You have not entered a matrix called " + theExpression + "." + cr + "You will probably get an error message now.");// alert("The matrix looked up is called " + theExpression.substring(0,posnExp) );// alert("leftMatrix number = " + leftMatrix);	var leftRowNum = bigMatrix[leftMatrix][maxRows][1];	var leftColNum = bigMatrix[leftMatrix][1][maxCols];	var exponent = eval(theExpression.substring(posnExp+1,theExpression.length))// The following gets the looked-up matrix	var tempMatrix = new makeArray2(leftRowNum, leftColNum);	for (var i = 1; i <= leftRowNum; i++)		{		for (j = 1; j <= leftColNum; j++) tempMatrix[i][j] = bigMatrix[leftMatrix][i][j];		} // i// alert("About to take the power with exponent = " + exponent);	if (exponent > 0) tempMatrix = Power(tempMatrix,exponent);	else if (exponent < 0) tempMatrix = Power(inverse(tempMatrix),-exponent);	// fix up bigMatrix by adding new data	for (var i = 1; i <= leftRowNum; i++)		{		for (j = 1; j <= leftColNum; j++) bigMatrix[numberActiveMatrices][i][j] = tempMatrix[i][j]		} // i	bigMatrix[numberActiveMatrices][maxRows][1] = leftRowNum;	bigMatrix[numberActiveMatrices][1][maxCols] = leftColNum;	bigMatrix[numberActiveMatrices][maxRows][maxCols] = "TEMP"+ numberActiveMatrices;			} // end of expelse if ( (posnTimes > -1) || (posnPlus > -1) || (posnMinus > -1) )	{// alert("here");	if (posnTimes > -1) theOperation = "times";	else if (posnPlus > -1) theOperation = "plus";	else theOperation = "minus";	numberActiveMatrices += 1;// alert ("numberActiveMatrices = " + numberActiveMatrices);	// too many steps?	if (numberActiveMatrices > maxNumberSteps) {document.theSpreadsheet.output.value = tooBigString; return("")}	// now do the work...	theExpression = stripSpaces(theExpression);	var posn = posnTimes;	if (theOperation == "plus") posn = posnPlus;	else if (theOperation == "minus") posn = posnMinus;		var leftTerm = theExpression.substring(0,posn);	var rightTerm = theExpression.substring(posn+1,theExpression.length)	// now take care of scalar multiplication	if (theOperation == "times")		{		if (looksLikeANumber(leftTerm)) 			{			theOperation = "leftScMult";			}		else if (looksLikeANumber(rightTerm))			{			theOperation = "rightScMult";			}		}// first dispense with scalar multiplcationif ( (theOperation == "leftScMult") ||( theOperation == "rightScMult") )		{		if (theOperation == "leftScMult") 			{			var theMatrix = lookup(rightTerm); 			var theScalar = eval(leftTerm);			if (theMatrix == -1) alert( "You have not entered a matrix called " + rightTerm + "." + cr + "You will probably get an error message now.");			}		else 			{ 			var theMatrix = lookup(leftTerm); 			var theScalar = eval(rightTerm);			if (theMatrix == -1) alert("You have not entered a matrix called " + leftTerm + "." + cr + "You will probably get an error message now.");			}		var RowNum = bigMatrix[theMatrix][maxRows][1];		var ColNum = bigMatrix[theMatrix][1][maxCols];		var tempMatrix = new makeArray2(RowNum, ColNum);		for (var i = 1; i <= RowNum; i++)			{			for (j = 1; j <= ColNum; j++) tempMatrix[i][j] = bigMatrix[theMatrix][i][j];			} // i		tempMatrix =  scmult(theScalar,tempMatrix);// fix up bigMatrix by adding new data		for (var i = 1; i <= RowNum; i++)			{			for (j = 1; j <= ColNum; j++) bigMatrix[numberActiveMatrices][i][j] = tempMatrix[i][j]			} // i		bigMatrix[numberActiveMatrices][maxRows][1] = RowNum;		bigMatrix[numberActiveMatrices][1][maxCols] = ColNum;		var theName = "TEMP";		if (bigMatrix[theMatrix][maxRows][maxCols].charAt(0) == "I") theName = "ITEMP";		bigMatrix[numberActiveMatrices][maxRows][maxCols] = theName + numberActiveMatrices;		} // end of scalar mult dont forget ELSE	else 		{	// not scalar mult; therefore addition or matrix mult		var leftMatrix = lookup(leftTerm); // alert("The matrix looked up is called " + theExpression.substring(0,posn) );// alert("leftMatrix number = " + leftMatrix);		if (leftMatrix == -1) alert( "You have not entered a matrix called " + leftTerm + "." + cr + "You will probably get an error message now.");		var rightMatrix = lookup(rightTerm);		if (rightMatrix == -1) alert("You have not entered a matrix called " + rightTerm + "." + cr + "You will probably get an error message now.");		// dimensions...		var firstLetterOfNameLeft  = bigMatrix[leftMatrix][maxRows][maxCols].charAt(0);// alert(bigMatrix[leftMatrix][maxRows][maxCols]);		var firstLetterOfNameRight  = bigMatrix[rightMatrix][maxRows][maxCols].charAt(0);		if ((firstLetterOfNameLeft == "I") || (firstLetterOfNameLeft == "$") )			{		var rightRowNum = bigMatrix[rightMatrix][maxRows][1];		var rightColNum = bigMatrix[rightMatrix][1][maxCols];		var leftRowNum = rightRowNum;		var leftColNum = rightRowNum;// alert("here " + leftRowNum + " " + rightRowNum);			}		else if  ((firstLetterOfNameRight == "I") || (firstLetterOfNameRight == "$"))			{		var leftRowNum = bigMatrix[leftMatrix][maxRows][1];		var leftColNum = bigMatrix[leftMatrix][1][maxCols];		var rightRowNum = leftColNum;		var rightColNum = leftColNum;			}		else			{		var leftRowNum = bigMatrix[leftMatrix][maxRows][1];		var leftColNum = bigMatrix[leftMatrix][1][maxCols];		var rightRowNum = bigMatrix[rightMatrix][maxRows][1];		var rightColNum = bigMatrix[rightMatrix][1][maxCols];			}		var tempMatrix1 = new makeArray2(leftRowNum, leftColNum);		for (var i = 1; i <= leftRowNum; i++)			{			for (j = 1; j <= leftColNum; j++) tempMatrix1[i][j] = bigMatrix[leftMatrix][i][j];			} // i		var tempMatrix2 = new makeArray2(rightRowNum, rightColNum);		for (var i = 1; i <= rightRowNum; i++)			{			for (j = 1; j <= rightColNum; j++) tempMatrix2[i][j] = bigMatrix[rightMatrix][i][j];			} // i		var tempMatrix = new makeArray2(leftRowNum, rightColNum);// alert("About to take the product/sum with exponent = " + exponent);	if (theOperation == "times") tempMatrix = times(tempMatrix1,tempMatrix2);	else if (theOperation == "plus") tempMatrix = plus(tempMatrix1,tempMatrix2);	else if (theOperation == "minus") tempMatrix = plus(tempMatrix1,scmult(-1,tempMatrix2));	// fix up bigMatrix by adding new data	for (var i = 1; i <= leftRowNum; i++)		{		for (j = 1; j <= rightColNum; j++) bigMatrix[numberActiveMatrices][i][j] = tempMatrix[i][j]		} // i	bigMatrix[numberActiveMatrices][maxRows][1] = leftRowNum;	bigMatrix[numberActiveMatrices][1][maxCols] = rightColNum;	bigMatrix[numberActiveMatrices][maxRows][maxCols] = "TEMP"+ numberActiveMatrices;		} // end of if not scalar mult	} // end of sum&productif (lastStep) {// alert("here");	var theNameHere = bigMatrix[numberActiveMatrices][maxRows][maxCols];	if ((theNameHere.length == 1) && (theNameHere != theOriginalExpr)) {		// okToRoll = false;		// alert("You have not defined a matrix called " + theOriginalExpr + ". The computation will not go forward.");		}// something wrong// alert(bigMatrix[numberActiveMatrices][maxRows][maxCols]);	if (okToRoll && !Reading) displayMatrix(numberActiveMatrices);	}else return(bigMatrix[numberActiveMatrices][maxRows][maxCols]); // the new matrix name is *1, *2, etc.} // Process *********************function displayMatrix(number) {var theString = "";theString += inputExpression + " = " + cr;// alert(singular);if (singular) theString += "undefined";else if (msFormat) 	{	var RowNum = bigMatrix[number][maxRows][1];	var ColNum = bigMatrix[number][1][maxCols];	var firstLetterOfName  = bigMatrix[number][maxRows][maxCols].charAt(0);	if (firstLetterOfName == "$") { RowNum = 1; ColNum = 1}	theString = "EQ " + backSlash+ "B"+backSlash+"BC"+ backSlash+"[("+ backSlash+"A"+ backSlash+"HS10"+ backSlash+"CO"+ColNum+"(";// alert(theString);	for (i = 1; i <= RowNum; i++)		{		for (j = 1; j <= ColNum; j++) 			{ 			if (fractionMode) x = toFrac (roundSigDig(bigMatrix[number][i][j],15), maxDenom, tol);  else			{			if (sigDigMode) x = roundSigDig(bigMatrix[number][i][j], numSigDigs).toString();			else x = roundDec(bigMatrix[number][i][j], numSigDigs).toString();			} // non fraction mode			theString += x;			if ( (i < RowNum) ||  (j < ColNum ) ) theString += ",";			} // j		} // i	theString += "))";	// alert(theString);	}else{var RowNum = bigMatrix[number][maxRows][1];var ColNum = bigMatrix[number][1][maxCols];var firstLetterOfName  = bigMatrix[number][maxRows][maxCols].charAt(0);if (firstLetterOfName == "$") { RowNum = 1; ColNum = 1}// alert("about to display a "+ RowNum+ " x " + ColNum + "matrix");// first round all the results and get the longest resulting stringvar maxLength = 1;var x = "", i=0, j=0, k=0;var xLen = 0;var displayTempMatrix = new makeArray2(RowNum,ColNum);for (i = 1; i <= RowNum; i++)	{	for (j = 1; j <= ColNum; j++) 		{ // not yet implementedif (fractionMode) x = toFrac (roundSigDig(bigMatrix[number][i][j],15) , maxDenom, tol);  	else 		{		if (sigDigMode) x = roundSigDig(bigMatrix[number][i][j], numSigDigs).toString();		else x = roundDec(bigMatrix[number][i][j], numSigDigs).toString();		} // non fraction mode			xLen = x.length; // alert("xLen =" + xLen);				if (xLen > maxLength) maxLength = xLen; 		displayTempMatrix[i][j] = x; 			} // j	} // i	var spaceString = "";	for (i = 1; i <= RowNum; i++)		{				for (j = 1; j <= ColNum; j++) 			{ 			x = displayTempMatrix[i][j];			sp = maxLength - x.length			spaceString = "";			for (k = 0; k <= sp; k++) spaceString += " ";			theString += x + spaceString + tab;			} // j		theString += cr;		} // i} // if not singulardocument.theSpreadsheet.output.value += theString + cr;// remove the plus above when done debugging// numberActiveMatrices = 0; // reset active matrices to 0;// alert(theString);return(0);}// ******* The following two fns return the position of the looked-up matrix // ******** in bigMatrix or bigMatrix2function lookup(InString) {var theResult = -1;for (var i = 1; i <= numberActiveMatrices; i++)	{	// if (i <= 3) alert("i = " + i + " " + bigMatrix[i][maxRows][maxCols]);	if (bigMatrix[i][maxRows][maxCols] == InString) theResult = i;	}return (theResult);} // lookupfunction lookup2(InString) {var theResult = -1;for (var i = 1; i <= numberNamedMatrices; i++)	{	if (bigMatrix2[i][maxRows][maxCols] == InString) theResult = i;	}return (theResult);} // lookup//*************************** end extractAndProcess *********************// ***** HERE ********// now search forward fot first tab and/or cr and return data// first just count tabs and returns using the parser function #returns = #rows// #columns = (#tabbs)/(#rows)function clearSpreadsheet(){if (browserName == "N") 	{ 	document.theSpreadsheet.power.value = "2"; 	document.theSpreadsheet.power2.value = "2";	var count = 0;	for (var i = 1; i <= 6; i++)		{ 		document.theSpreadsheet.vector[i-1].value = "";		for (var j = 1; j <= 6; j++)			{			document.theSpreadsheet.string[count].value = "";			count++;			} // j		} // i	}else if (browserName == "M")	{	for (var i = 0; i <=41; i++) document.theSpreadsheet[i].value = "";	document.theSpreadsheet.power.value = "2"; 	document.theSpreadsheet.power2.value = "2";	}}function clearAnswer(){if (browserName == "N")	{	var count = 0;	for (var i = 1; i <= 6; i++)		{ 		for (var j = 1; j <= 6; j++)			{			document.theAnswer.string[count].value = "";			count++;			} // j		} // i	}else if (browserName == "M")	{	for (var i = 0; i <=35; i++) document.theAnswer[i].value = "";	}}function makeArray3 (X,Y,Z)	{	var count;	this.length = X+1;	for (var count = 1; count <= X+1; count++)		// to allow starting at 1		this[count] = new makeArray2(Y,Z);	} // makeArray3function makeArray2 (X,Y)	{	var count;	this.length = X+1;	for (var count = 1; count <= X+1; count++)		// to allow starting at 1		this[count] = new makeArray(Y);	} // makeArray2function makeArray (Y)	{	var count;	this.length = Y+1;	for (var count = 1; count <= Y+1; count++)		this[count] = 0;	} // makeArrayfunction det(A)	{	var Length = A.length-1;// alert(Length);		// formal length of a matrix is one bigger	if (Length == 1) return (A[1][1]);	else		{		var i;		var sum = 0;		var factor = 1;		for (var i = 1; i <= Length; i++)			{			if (A[1][i] != 0)				{				// create the minor				minor = new makeArray2(Length-1,Length-1);				var m;				var n;				var theColumn;				for (var m = 1; m <= Length-1; m++) // columns					{					if (m < i) theColumn = m;					else theColumn = m+1;					for (var n = 1; n <= Length-1; n++)						{						minor[n][m] = A[n+1][theColumn];// alert(minor[n][m]);						} // n					} // m				// compute its determinant				sum = sum + A[1][i]*factor*det(minor);				}			factor = -factor;	// alternating sum			} // end i		} // recursion// alert(sum);	return(sum);	} // end determinantfunction inverse(A) {	var Length = A.length - 1;	B = new makeArray2(Length, Length);  // inverse	var d = det(A);	if ( (Length == 1) && (d != 0) ) 		{		B[1][1] = 1/A[1][1];		return (B);		}	if (d == 0) 		{		alert("singular matrix--check data");		singular = true;		}	else		{		var i;		var j;		for (var i = 1; i <= Length; i++)			{			for (var j = 1; j <= Length; j++)				{				// create the minor				minor = new makeArray2(Length-1,Length-1);				var m;				var n;				var theColumn;				var theRow;				for (var m = 1; m <= Length-1; m++) // columns					{					if (m < j) theColumn = m;					else theColumn = m+1;					for (var n = 1; n <= Length-1; n++)						{						if (n < i) theRow = n;						else theRow = n+1;						minor[n][m] = A[theRow][theColumn];// alert(minor[n][m]);						} // n					} // m				// inverse entry				var temp = (i+j)/2;				if (temp == Math.round(temp)) factor = 1;				else factor = -1;								B[j][i] =  det(minor)*factor/d; 								} // j						} // end i		} // recursion	return(B);	} // end inversefunction Power(theMatrix,n){	// first square it up a few times;if ( (browserName == "N") || (browserName == "M") )	{ 		var negExponent = false;	with (Math)		{		var Length = theMatrix.length-1;		theProd = new makeArray2(Length, Length);		if (n < 0) { negExponent = true; n = -n}		theProd = theMatrix;		var m = floor(log(n)/log(2));		for (var j = 1; j <= m; j++) theProd= times(theProd, theProd);		var leftover = n - round(pow(2,m));		for (var j = 1; j <= leftover; j++) theProd = times(theMatrix,theProd);		} // end with Math 	if (negExponent) theProd = inverse(theProd);	return (theProd);	}}function times(theMatrixA, theMatrixB) 	{  	var Length1 = theMatrixA.length-1;	var Length2 = theMatrixB[1].length-1; 	var Length3 = theMatrixA[1].length-1;	if (Length3 != theMatrixB.length - 1) {		alert("Two matrices in the expression " + theOriginalExpr + " cannot be multiplied because the dimensions are wrong.");		okToRoll = false;		errorFlag = 0;		}	else	{		theProduct = new makeArray2(Length1, Length2);		for (var i = 1; i <= Length1; i++)		{		for (var j = 1; j <= Length2; j++)			{			theProduct[i][j]=0;			for (var k = 1; k <= Length3; k++)				{				theProduct[i][j]+=theMatrixA[i][k]*theMatrixB[k][j];				}// k			} // j		} // i// *** testing *******// var theString2 = "AB = " + cr;// for (var i = 1; i <= Length1; i++)//	{//	for (var j = 1; j <= Length2; j++) theString2 += theProduct[i][j] + tab;//	theString2 += cr;//	}// theString2 += "B = "+cr;// for (var i = 1; i <= Length3; i++)//	{//	for (var j = 1; j <= Length2; j++) theString2 += theMatrixB[i][j] + tab;//	theString2 += cr;//	}// document.theSpreadsheet.output.value += theString2;// *** testing *******		return (theProduct);	} //end else		}// *** Scalar Multiplicationfunction scmult(theScalar, theMatrix) 	{  	var Length1 = theMatrix.length-1;	var Length2 = theMatrix[1].length-1; 	theAnswer = new makeArray2(Length1, Length2);	for (var i = 1; i <= Length1; i++)	{	for (var j = 1; j <= Length2; j++)		{		theAnswer [i][j]= theScalar*theMatrix[i][j];		} // j	} // i	return (theAnswer);	}function plus(theMatrixA, theMatrixB) 	{  	var Length1 = theMatrixA.length-1;	var Length2 = theMatrixA[1].length-1; 	var Length3 = theMatrixB.length-1;	var Length4 = theMatrixB[1].length-1;	if ((Length1 != Length3)|| (Length2 != Length4)) {		alert("Two matrices in the expression cannot be added because their dimensions do not match.");		okToRoll = false;		errorFlag = 0;		}	else {		theSum = new makeArray2(Length1, Length2);		for (var i = 1; i <= Length1; i++)		{		for (var j = 1; j <= Length2; j++)			{			theSum[i][j]= theMatrixA[i][j]+theMatrixB[i][j];			} // j		} // i		return (theSum);		} // end else	}function stripSpaces (InString)  {	OutString="";	for (Count=0; Count < InString.length; Count++)  {		TempChar=InString.substring (Count, Count+1);		if (TempChar!=" ")			OutString=OutString+TempChar;		}	return (OutString);	}function doIt(){		fractionMode = document.theSpreadsheet.fracModeButton.checked;	var num = doIt.arguments[0];	//**********	// Option 1 clear	if (num == 1)		{				}	// Option 2	else  if (num == 2)		{				}		// Option 3 (Erase)	else  if (num == 3)		{				if ( (document.theSpreadsheet.input.value != "") || (document.theSpreadsheet.output.value != "") ||  (document.theSpreadsheet.expr.value != "") ) {			var answer = confirm('Are you sure you want to erase everything? You might not be able to recover it.');// alert(theStuff);			if(answer) {				storedInput = document.theSpreadsheet.input.value;				storedOutput = document.theSpreadsheet.output.value;				storedExpr = document.theSpreadsheet.expr.value;				document.theSpreadsheet.input.value = "";				document.theSpreadsheet.output.value = "";				document.theSpreadsheet.expr.value = "";				} // if they said ok				} // if at least one field is not blank		else {			document.theSpreadsheet.input.value = storedInput;			document.theSpreadsheet.output.value = storedOutput;			document.theSpreadsheet.expr.value = storedExpr;			}		} // end of Option 3	// compute the expression	else  if (num == 4)		{ // alert ("here");		// reset some global variables		numberActiveMatrices = 0;		numberNamedMatrices = 1;		for (var i = 1; i <= maxNumberSteps; i++) bigMatrix[i][maxRows][maxCols] = 0;		for (var i = 2; i <= maxNumberMatrices; i++) {			bigMatrix2[i][maxRows][maxCols] = 0}		// reininntialize the identity (it tends to get lost),,		for (var i = 1; i <= maxRows-1; i++)			{			for (var j = 1; j <= maxCols-1; j++)				{				if (i == j) bigMatrix2[1][i][j] = 1;				else bigMatrix2[1][i][j] = 0;				} // j			} // i		bigMatrix2[1][maxRows][1] = maxRows-1; // default is a big matrix		bigMatrix2[1][1][maxCols] = maxCols-1;		bigMatrix2[1][maxRows][maxCols] = "I";		// end of defining the identity		okToRoll = true;		readSpreadsheet();			var accuracydig = document.theSpreadsheet.acc.value;		var theIndex1 = document.theSpreadsheet.S.selectedIndex;		if  (document.theSpreadsheet.S.options[theIndex1].text == "significant digits") sigDigMode = true;		else sigDigMode = false;		if ( (accuracydig == "") || (!looksLikeANumber(accuracydig)) ) { document.theSpreadsheet.output.value = "Enter a value for the accuracy (Rounding) in the range 1-13."; okToRoll = false}		if (okToRoll)			{ 			var thenum = eval(accuracydig); 			if ((thenum < 1) || (thenum > 14)) {document.theSpreadsheet.output.value = "Accuracy (Rounding) must be in the range 1-13."; okToRoll = false}			else numSigDigs =thenum;					} // if okToRoll			msFormat = document.theSpreadsheet.msFormatButton.checked;		var theExpression = "";		var theInputString = stripSpaces(document.theSpreadsheet.expr.value);		var exprs = parser(theInputString,",");// alert(exprs[0] + "    " + exprs[1] + "    " + exprs[2])		// clear output		document.theSpreadsheet.output.value = "";		for (var numFormula = 1; numFormula <= exprs[0]; numFormula++) {			theExpression = exprs[numFormula];			theOriginalExpr = theExpression; // want to refer to it later			if ((okToRoll) && (theExpression == "") && (exprs[0] <= 1) ) document.theSpreadsheet.output.value += "You must enter formulas(s) to evaluate!";			else if ((okToRoll) && (theExpression == "")) document.theSpreadsheet.output.value += "There must be an expression after each comma.";								else if (okToRoll) 				{ 			// First we need to read in the named marices to the active ones.				// ***HERE				// readSpreadsheet();				numberActiveMatrices = numberNamedMatrices+1;				for (var i = 1; i <= numberNamedMatrices; i++) {				bigMatrix[i] = bigMatrix2[i]// alert(i + ", " + bigMatrix[i][maxRows][maxCols]);					} 				inputExpression = theExpression; // this is for displaying the matrix			// alert(theExpression);						theExpression = preProcess(theExpression);// alert(theExpression);						extractAndProcess(theExpression);								} // if okToRoll			} // end loop			} // of this option	// Option 5	else  if (num == 5)		{		document.theSpreadsheet.input.value = theSampleMatrixString;		document.theSpreadsheet.expr.value = "A, det(A), (A+B)*C, reduce(S), (I-A)^-1, D";		document.theSpreadsheet.output.value = "Press 'Compute' to calculate the above expressions." + cr + sampleExpressions;		}	// Option 6 	else  if (num == 6)		{							} // if num = 6// Option 7	else  if (num == 7)		{		var theCookieValue = document.theSpreadsheet.input.value;		if (cookiesEnabled && (stripSpaces(theCookieValue) != '')) {	// *** Open a window			verifyList(); // reconcile save list with older saved files			var now = new Date();			var tomorrow = new Date(now.getTime() + 1000 * 60 * 60 * 24);			var nextyear = new Date(now.getTime() + 1000 * 60 * 60 * 24 * 365);			var twosecs = new Date(now.getTime() + 1000 * 2);			var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);			var twomin = new Date(now.getTime() + 1000 * 60 * 2)			setCookie('temp1', theCookieValue, twomin);			var x = sesame("matrixSave.html",500,150);			} // if cookies are enabled		else if (!cookiesEnabled) alert("Cookies are not enabled on your computer, so Save will not work.");		else alert("You have no matrices to save in your input area.");		} // if num = 7// Option 8	else  if (num == 8)		{		if (cookiesEnabled) {			var theS = getCookie('temp');			var now = new Date();			var tomorrow = new Date(now.getTime() + 1000 * 60 * 60 * 24);			var nextyear = new Date(now.getTime() + 1000 * 60 * 60 * 24 * 365);			var twosecs = new Date(now.getTime() + 1000 * 2);			var yesterday = new Date(now.getTime() - 1000 * 60 * 60 * 24);			setCookie('temp', '', yesterday);// if(theS == null) alert(theS);			if ((theS == null) || (theS == '')) theS = "hello";						else document.theSpreadsheet.input.value = theS;			for (var i = 1; i <= 100; i++) {theS = ''}			} // if cookies are enabled		} // if num = 8// Option 9	else  if (num == 9)		{		var now = new Date();		var twosecs = new Date(now.getTime() + 1000 * 2)		setCookie('cookieTest','You will meet a tall dark stranger.', twosecs);		var testing = getCookie('cookieTest');		if(testing == null) {alert("Cookies are disabled on your computer. 'Save' and 'Open' will not work unless cookies are enabled."); cookiesEnabled = false}		} // if num = 9}
