// Notes
// (1) Need a simplifier to simplify structures eg sin * sin = sin squared
// conbst times sine times sine etc


var thebgColor = "DDFFDD";
var X = 0;
var x = 0;
var y = 0;
var h = 0;
var xh = 0;
var hx = 0;
var t = 0;
var th = 0;
var ht = 0;
var a = 0;
var b = 0;
var guesses = 0;
var quoteMark = unescape( '%22' );
var singlequoteMark = unescape( '%27' );
var biggestDenom = 10000;
var trigFunctions = false;

// *** Error Handler ******
function myErrorTrap(message,url,linenumber) {
this.parent.bottom.window.location = "wrong.html";
return (true);
} // end of on error
// ********************

function buttonString(theName,theCode) {
var buttonStr = '<td><input type="button" class = "myButtons" onmouseover="this.className= ' + singlequoteMark + 'myButtons myButtonsHov' + singlequoteMark + '" onmouseout="this.className= ' + singlequoteMark + 'myButtons' + singlequoteMark + '"  value = "' + theName + '" onClick=' + theCode + '></td>';
return(buttonStr);
} // buttonString


function radicalString(radicand) {
var theStr = '<span style = "vertical-align: -2px">&radic;</span><span style="border-top:1px solid black;"><img src = "../gf/thinspace.gif" width = 2>' + radicand + '<img src = "../gf/thinspace.gif" width = 2></span>';
return(theStr);
} // radicalString



function HideContent(d) {
document.getElementById(d).style.visibility = "hidden";
}
function ShowContent(d) {
document.getElementById(d).style.visibility = "visible";
}

function ToggleVisibility(d) {
// alert(document.getElementById(d).style.visibility);
if (document.getElementById(d).style.visibility == "hidden") document.getElementById(d).style.visibility = "visible";
else document.getElementById(d).style.visibility = "hidden";
}


function putAnExerciseString(theNumberColor, theNumber, theEquation, theCorrectAnswer, equationFieldLength, formatSolution, theSolutionFormattedArray) {
if (formatSolution) {
	var theResult = '<table callspacing = 0><tr><td><b><font color = ' + theNumberColor + '>' + theNumber + '.&nbsp;</font></b></td><TD><TABLE><TR><td nowrap><font class = math>f</font>(<font class = math>x</font>) =</td>' + theEquation;
	theResult += '<td nowrap><DIV id = SOLFIELD' + theNumber +  ' style = " visibility: hidden;"><span style = "TABLE, TR, TD {color: purple} "><table><tr><td><font color = purple> &nbsp; &nbsp; Answer:</font></td>' + theSolutionFormattedArray[1] + '</tr></table></span></DIV></td>';
	theResult += '</TR></TABLE></TD></tr>';
	var theResult2 = '<tr><td nowrap></td><TD><TABLE><TR><td><font class = math>f</font><font face = "Courier">' + singlequoteMark + '</font>(<font class = math>x</font>) =</td>';
	theResult2 += '<td><input type=text size= ' + equationFieldLength.toString() + ' value="" name = "Q' + theNumber + '"></td></TR></TABLE></TD>';
	var theFunction = 'var vv = checkAnswerandValue("theForm", "Q' + theNumber + '", "' + theCorrectAnswer  + '", 1, 600, .0005, "x=13", " " , " " ); if (vv == 1) document.images["pic' + theNumber + '"].src = "elts/smallcheck.gif"; else if (vv == 0) document.images["pic' + theNumber + '"].src = "elts/smallq.gif"; else document.images["pic' + theNumber + '"].src = "elts/smallx.gif";';
	var theWrappedFunction = singlequoteMark + theFunction + singlequoteMark;
	var thePeekFunction = 'togglePeek("theForm", "Q' + theNumber + '", "' + theCorrectAnswer  + '");';
	thePeekFunction += 'ToggleVisibility("SOLFIELD' + theNumber + '");';
// alert(thePeekFunction);
		var theWrappedPeekFunction = singlequoteMark + thePeekFunction+ singlequoteMark;
	
	theResult2 += '</tr><tr><td></td><TD><TABLE><TR>' + buttonString('Verifica', theWrappedFunction);
	theResult2 += buttonString('Vistazo', theWrappedPeekFunction);
	theResult2 += '<td><img src = "elts/smallblank.gif" name = "pic' + theNumber + '"></td></TR></TABLE></TD></tr></table>';
	var theText1 = document.getElementById('EXDiv' + theNumber);
	theText1.innerHTML = theResult + theResult2;
	} // if formatSolution

else {
	var theResult = '<table><tr><td><b><font color = ' + theNumberColor + '>' + theNumber + '.</font></b></td><td><font class = math>f</font>(<font class = math>x</font>) =</td>' + theEquation + '</tr></table>';
var theResult2 = '<table><tr><td><font class = math>f</font><font face = "Courier">' + singlequoteMark + '</font>(<font class = math>x</font>) =</td>';
	theResult2 += '<td><input type=text size= ' + equationFieldLength.toString() + ' value="" name = "Q' + theNumber + '"></td><td><img src = "elts/smallblank.gif" name = "pic' + theNumber + '"></td>';
	var theFunction = 'var vv = checkAnswerandValue("theForm", "Q' + theNumber + '", "' + theCorrectAnswer  + '", 1, 600, .0005, "x=13", " " , " " ); if (vv == 1) document.images["pic' + theNumber + '"].src = "elts/smallcheck.gif"; else if (vv == 0) document.images["pic' + theNumber + '"].src = "elts/smallq.gif"; else document.images["pic' + theNumber + '"].src = "elts/smallx.gif";';
	var theWrappedFunction = singlequoteMark + theFunction + singlequoteMark;
	var thePeekFunction = 'togglePeek("theForm", "Q' + theNumber + '", "' + theCorrectAnswer  + '");';
	var theWrappedPeekFunction = singlequoteMark + thePeekFunction+ singlequoteMark;
	theResult2 += buttonString('Verifica', theWrappedFunction);
	theResult2 += buttonString('Vistazo', theWrappedPeekFunction);
	theResult2 += '</tr></table>';
	var theText1 = document.getElementById('EXDiv' + theNumber);
	theText1.innerHTML = theResult;
	var theText2 = document.getElementById('EXDivB' + theNumber);
	theText2.innerHTML = theResult2;
	} // if no solution

} // putAnExerciseString

function writeHeading(theTitle) {
var theText = '<center><table width = 90%><tr><td nowrap class = myButtons width = 80 align = center>' + theTitle + '</td><td nowrap><img src = ' + quoteMark + 'elts/buttonbg.gif' + quoteMark + ' width = 100% height = 4></td></tr></table></center>'
document.writeln(theText);
}

function drawLine() {
var theText = '<center><table width = 90%><tr><td><img src = ' + quoteMark + 'elts/buttonbg.gif' + quoteMark + ' width = 100% height = 4></td></tr></table></center>'
document.writeln(theText);
}

// ********* Exercise display routines ************
function randomInt(a,b) {
// returns a random integer in the range [a, b]
return(a + Math.floor(Math.random()*(b-a+1)));
}

function putFancyDerivExercises(rule, level) {
if (level == 1) theNumberColor = "33AA00";
else if (level == 2) theNumberColor = "BB5500";
else if (level == 3) theNumberColor = "FF0000";
var theEXCorrectAnswers = new Array();
var theEXCorrectAnswersFormatted = new Array();
var coeffType = 1;
var theDepth = 1;
var operatorStr = 'T'; // product
var complexity = 1;
if (level >= 2) complexity = 2;
var variableName = 'x';
var parameterType = 1; // rational
var exponentType = 1; // integer
var randomizingOperators = false;
var equationFieldLength = 70;
equationFieldLength += level*20;

for (var exerNum = 1; exerNum <= 20; exerNum++) {
if (exerNum <= 3) {
	parameterType = 2;
	if ((level == 2) && (exerNum <= 1)) parameterType = 1;
	if ((level == 1) && (exerNum <= 2)) parameterType = 1;
	// some instructions for later
	}
else if (exerNum <= 6) {
	// some rational expressions
	parameterType = 2;
	if ((level == 2) && (exerNum <= 4)) parameterType = 1;
	if ((level == 1) && (exerNum <= 5)) parameterType = 1;
	operatorStr = 'Q';
	}
else if (exerNum <= 8) {
	// some combinations
	operatorStr = 'TS';
	theDepth =2;
	}

else if (exerNum <= 10) {
	// some more combinations
	operatorStr = 'TTC';
	theDepth = 2;
	if (level == 3) theDepth = 3;
	}

else if (exerNum <= 12) {
	// some more combinations
	operatorStr = 'TTT';
	theDepth = 2;
	if (level == 3) theDepth = 3;
	}

else if (exerNum <= 15) {
	// some more combinations
	operatorStr = 'TQSS';
	if (level == 2) complexity = 1;
	theDepth = 2;
	if (level == 3) theDepth = 3;
	}

else if (exerNum <= 20) {
	// some more combinations
	operatorStr = 'QTTT';
	complexity = 1; 
	theDepth = 2;
	if (level == 1) parameterType = 1;
	if (level >= 2) complexity = 1;
	if (level == 3) theDepth = 4;
	}

if (!trigFunctions) var theExpr = createExpression2(operatorStr, theDepth, complexity, parameterType, exponentType, variableName, randomizingOperators);
else var theExpr = createExpression2(operatorStr, theDepth, complexity, parameterType, exponentType, variableName, randomizingOperators,["cosx","sinx"]);
// alert(theExpr);
var theFormattedExpr = format(theExpr,true,true,true);
var theFormattedAnswer = format(deriv(theExpr),true,true,true);
theEXCorrectAnswers[exerNum] = theFormattedAnswer[0]
theEXCorrectAnswersFormatted[exerNum] = theFormattedAnswer[1];
putAnExerciseString(theNumberColor, exerNum.toString(),theFormattedExpr[1], theEXCorrectAnswers[exerNum],equationFieldLength,true, theFormattedAnswer);


 } // exerNum

} // putFancyDerivExercises

function putDerivExercises(level) {
var theLevelCode = level + .1;
// the term after the decimal is the number of monomials in the expression
var theString = '' // this will be a typical exercise
var theNumberColor;
var negExponents = true;
var asRadicals = false;
var levelStar = 0; // adjusted level
if (level == 1) theNumberColor = "33AA00";
else if (level == 2) theNumberColor = "BB5500";
else if (level == 3) theNumberColor = "FF0000";
levelStar = level; 
if (levelStar > 2) levelStar =  2;
// start with integer coefficients and then proceed to fractions.
var theEXCorrectAnswers = new Array();
var theEXCorrectAnswerFormatted = new Array();
var theText = '';
for (var exerNum = 1; exerNum <= 20; exerNum++) {
	var coeffType = 1;
	// decide on whether to allow negative exponents
	if (Math.round(Math.random()) == 0) negExponents = true; 
	else negExponents = false;
	if (exerNum >= 3) coeffType = 3;
	if (exerNum >= 5) coeffType = 2;
	if ((exerNum >= 5) && (exerNum <= 6)) { asRadicals = true;} 
	if (exerNum >= 7) {coeffType = 3; theLevelCode = levelStar + .3};
	if (exerNum >= 9) {coeffType = 2; theLevelCode = levelStar + .3};
	if (exerNum >= 12) {coeffType = 2; theLevelCode = levelStar + .2};
	if (exerNum >= 14) negExponents = false; asRadicals = true;
	if (exerNum >= 16) {coeffType = 3; theLevelCode = levelStar + .1};
	if (exerNum >= 18) {coeffType = 2; theLevelCode = levelStar + .2};
	// these will be sums of polys

	if (exerNum < 12) {
		// single polynomials
	
		var degree = randomInt(0, 10); // degree of the monomial
		if (exerNum > 9) degree += randomInt(0, 1)/2;
		var shift = randomInt(0, 10);
// alert('EXDiv'+ exerNum.toString());

if ((exerNum == 3) || (exerNum == 4)) degree += eval(roundDec(randomInt(0, 10)/10,1));
		var theArray = createPoly(degree, shift, coeffType, 'x', theLevelCode);
		var theOutput = formatPoly(theArray,negExponents,false, asRadicals);
//		theString = '<table><tr><td><b><font color = ' + theNumberColor + '>' + exerNum.toString() + '.</font></b></td>' + theOutput[1] + '</tr></table>';
		var theArray2 = polyDeriv(theArray,1); 
		theEXCorrectAnswers[exerNum] = formatPoly(theArray2,negExponents,false)[0];
putAnExerciseString(theNumberColor, exerNum.toString(), theOutput[1], theEXCorrectAnswers[exerNum],60,false);
		
// * testing
theString += '<font face = "Courier" color = blue>' + theOutput[0] + '</font>';
theString += '<br><font face = "Courier" color = red>' + theEXCorrectAnswers[exerNum] + '</font>';
// if ((exerNum <= 3) || (exerNum == 4)) theString += '<br><font color = purple>' + theArray;
		theEXCorrectAnswerFormatted[exerNum] = formatPoly(theArray2)[1];
//  alert (theFRCorrectAnswers[exerNum]);
		} // single polynomials
	else if (exerNum <= 15) {
		// sum of two polynomials
		var degree1 = randomInt(0, 10); // degree of the monomial
		if (level < 3) degree1 += randomInt(0, 1)/2;
		if ((level == 3) && (exerNum >= 14)) degree1 += randomInt(0, 2)/3;
		var shift1 = randomInt(0, 5);
		var degree2 = 1/2; // degree of the monomial
		var shift2 = randomInt(6, 10);
// alert('EXDiv'+ exerNum.toString());

		var theArrayA = createPoly(degree1, shift1, coeffType, 'x', theLevelCode);
		var theOutputA = formatPoly(theArrayA, negExponents,true, asRadicals);
		var theArrayB = createPoly(degree2, shift2, coeffType, 'x', theLevelCode);
		var theOutputB = formatPoly(theArrayB, negExponents,true, asRadicals);
			var theConnectingSign = "<td> + </td>";
		if (theOutputB[0].charAt(0) == "-") theConnectingSign = ' ';
//		theString = '<table><tr><td><b><font color = ' + theNumberColor + '>' + exerNum.toString() + '.</font></b></td>' + theOutputA[1] + theConnectingSign +  theOutputB[1] +'</tr></table>';
		var theArray2A = polyDeriv(theArrayA,1);
		var theArray2B = polyDeriv(theArrayB,1);
		
		var theAnswer1 = formatPoly(theArray2A, negExponents,true)[0] + '+' + formatPoly(theArray2B, negExponents,true)[0];
		theAnswer1 = replaceSubstring(theAnswer1,"+-"," - ");
		theAnswer1 = replaceSubstring(theAnswer1," + ","+");
		theAnswer1 = replaceSubstring(theAnswer1,"+"," + ");
		theEXCorrectAnswers[exerNum] = theAnswer1;
		
		putAnExerciseString(theNumberColor, exerNum.toString(),theOutputA[1] + theConnectingSign +  theOutputB[1], theEXCorrectAnswers[exerNum],60,false);
//  alert (theEXCorrectAnswers [exerNum],60,false);

// * testing
theString += '<font face = "Courier" color = blue>' + theOutputA[0] + ' + ' + theOutputB[0] + '</font>';
theString += '<br><font face = "Courier" color = red>' + theEXCorrectAnswers[exerNum] + '</font>';

		} // sums of polynomials

	else if (exerNum <= 17) {
		// radicals top and bottom
		var degree = 1;
		asRadicals = true;
		negExponents = false;
		coeffType = 2;
		if (level <= 2) var theArray = createPoly(degree, 1/2, coeffType, 'x', 2.2);
		else var theArray = createPoly(3, 3/2, coeffType, 'x', 2.3);
		var theOutput = formatPoly(theArray, negExponents, true, asRadicals);
		// theString = '<table><tr><td><b><font color = ' + theNumberColor + '>' + exerNum.toString() + '.</font></b></td>' + theOutput[1] + '</tr></table>';
		var theArray2 = polyDeriv(theArray,1);
		theEXCorrectAnswers[exerNum] = formatPoly(theArray2, negExponents,true)[0];

		putAnExerciseString(theNumberColor, exerNum.toString(),theOutput[1], theEXCorrectAnswers[exerNum],60,false);

// * testing
theString += '<font face = "Courier" color = blue>' + theOutput[0] + '</font>';
theString += '<br><font face = "Courier" color = red>' + theEXCorrectAnswers[exerNum] + '</font>';

		} // radicals

	else {
		// radicals top and bottom
		var degree = 3;
		asRadicals = true;
		negExponents = false;
		coeffType = 2;
		var negDegree = 3/2;
		theLevelCode = 2.2;
		if (exerNum >= 19) {degree = 3; negDegree = 5/2; theLevelCode = 2.3;}  
		if (level <= 2) var theArray = createPoly(degree, negDegree, coeffType, 'x', theLevelCode);
		else if (exerNum <= 19) var theArray = createPoly(degree+1, 5/2, coeffType, 'x', 2.4);
		else var theArray = createPoly(degree+2, 7/2, coeffType, 'x', 2.5);
		var theOutput = formatPoly(theArray, negExponents, true, asRadicals);
		// theString = '<table><tr><td><b><font color = ' + theNumberColor + '>' + exerNum.toString() + '.</font></b></td>' + theOutput[1] + '</tr></table>';
		var theArray2 = polyDeriv(theArray,1);

		theEXCorrectAnswers[exerNum] = formatPoly(theArray2, negExponents,true)[0];

		putAnExerciseString(theNumberColor, exerNum.toString(),theOutput[1], theEXCorrectAnswers[exerNum],60,false);

// alert(theArray2);

// * testing
theString += '<font face = "Courier" color = blue>' + theOutput[0] + '</font>';
theString += '<br><font face = "Courier" color = red>' + theEXCorrectAnswers[exerNum] + '</font>';

		} // radicals

//	theText = document.getElementById('EXDiv'+ exerNum.toString());
//	theText.innerHTML = theString;



// document.getElementById('EXDiv1').innerHTML = theString;
// now the derivatives:
	// alert (theEXCorrectAnswers [exerNum]);
	} // exerNum
} // putDerivExercises








// ** end exercise dispkay routines

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(url,"win1",tb);
	Win_1.focus();
    }


function stripSpaces (InString)  {
	OutString=""; 
	if (InString == "") return (OutString);
	for (Count=0; Count < InString.length; Count++)  {
		TempChar=InString.substring (Count, Count+1);
		if (TempChar!=" ")
			OutString=OutString+TempChar;
	}
	return (OutString);
}

function stripChar (InString,symbol)  {
	OutString="";
	for (Count=0; Count < InString.length; Count++)  {
		TempChar=InString.substring (Count, Count+1);
		if (TempChar!=symbol)
			OutString=OutString+TempChar;
	}
	return (OutString);
}

function replaceChar (InString,oldSymbol,newSymbol)  {
	OutString="";
	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 makeArray (NumElements, Fill)  {
	var Count;
	this.length = NumElements;
	for (Count = 1; Count <= NumElements; Count++)  {
		this[Count] = Fill;
	}
	return (this);
}

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 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 parser (InString, Sep)  {
	NumSeps=1;
	for (Count=1; Count < InString.length; Count++)  {
		if (InString.charAt(Count)==Sep)
			NumSeps++;
	}
	parse = new makeArray (NumSeps+4, "");		// my adjustments
	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 winopen(){
// opens a window in the bottom frame
	var str = winopen.arguments[0];
	var loc = winopen.arguments[1];
	if (navigator.appName == "Microsoft Internet Explorer") this.parent.bottom.window.location = str;
	else window.open(str,loc);
} // winopen



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 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
		}
} // roundSigDig

function roundDec(theNumber, numPlaces) {
with (Math)
	{
	var x =shiftRight(round(shiftRight(theNumber,numPlaces)),-numPlaces);
	return x;
	} // with math
} // roundDec


function toFrac(x, maxDenom) {
	var theFrac = new Array();
	theFrac[1] = 0;
	theFrac[2] = 0;
	theFrac[3] = ''; // will be the fraction string
	theFrac[4] = 0; // will be 1 if the fraction has a slash
	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
	var n = 0;
	var d = 0;
	var p = 0;
	var q = 0;

	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;
	var theFracString = '';
	if (n == 0) theFracString = "0";
	else if (d == 1) theFracString = n.toString();
	else if (n < 0) {
		theFrac[4] = 1; // has a slash
		theFracString = "-" + (-n).toString() + "/" + d. toString()
		}
	else {
		theFrac[4] = 1; 
		theFracString = n.toString() + "/" + d. toString()
		}
	theFrac[3] = theFracString;

	return(theFrac);

} // toFrac


// ********* FUNCTION PARSER ***********
function myEval(theString)
{
theString = replaceSubstring (theString,"cos","Math.cos");
theString = replaceSubstring (theString,"sin","Math.sin");
theString = replaceSubstring (theString,")(",")*(");
theString = replaceSubstring (theString,")ln",")*ln");
theString = replaceSubstring (theString,"sqrt","Math.sqrt");
theString = replaceChar (theString,"[","(");
theString = replaceChar (theString,"]",")");
theString = replaceChar (theString,"{","(");
theString = replaceChar (theString,"}",")");
return(eval(myParse(theString)));
	
}


function myEvalAt(theString,theNumber)
{
x = theNumber;
t = theNumber;
return(myEval(theString))
}




// The above function requires all the following routines
function breakApart(InString) {
	// ******* Input: any string such as aaa*bbb or (aa*aa)*bbb
	// *** This Routine Retuns two pieces
	// *** bbb starts at the left-most operation *, /,  - or +
	// *** if it sees a paren, it stops after closure.

	theString = InString;
	var Length = theString.length;
	var outArray = new Array();
	outArray[1] = theString;
	outArray[2] = "";
	var parenCount = 0;
	var parenWatch = false;
	var looking = true;
	
	
	if (theString.substring (0,1) == "(")
		{
		parenCount++;
		parenWatch = true;
		looking = false;
		}
	// Look for operators
	
	for (Count=1; Count < Length; Count++)  
		{
		TempChar=theString.substring (Count, Count+1);
		if (TempChar == "(") 
			{parenCount ++;}
		else if (TempChar == ")") {parenCount = parenCount-1};

		if ((parenCount == 0) && (parenWatch == true))
			 {
			parenWatch = false;
			outArray[1] = theString.substring (0, Count+1);
			outArray[2] = theString.substring (Count+1, Length);
			}

		if (looking == true)
			{
		if ( ( (TempChar == "*") || (TempChar == "/") || (TempChar == "-")  ) || ( (TempChar == "+") || (TempChar == ')' )  )  )
				{ 
				
					{
					// alert(Count);
					looking = false;
					outArray[1] = theString.substring (0, Count);
					outArray[2] = theString.substring (Count, Length);
					// alert (outArray[1]);
					// alert(outArray[2]);
					} // end if hit one
				} 

			} // end if looking

		} // end of loop


	return (outArray);

} // end of breakApart

function isNumberChar (InString)  {
	if(InString.length!=1) 
		return (false);
	RefString="1234567890)";
	if (RefString.indexOf (InString, 0)==-1) 
		return (false);
	return (true);
}

function isCharHere (InString, RefString)  {
	if(InString.length!=1) 
		return (false);
	if (RefString.indexOf (InString, 0)==-1) 
		return (false);
	return (true);
}

function putProduct(InString) {
OutString="";
for (Count=0; Count < InString.length; Count++)  {
		TempChar=InString.substring (Count, Count+1);
		if (!isCharHere(TempChar,"xXeslcapdDuUhHtT(") || (Count == 0) )
			{OutString=OutString+TempChar}
		else 
			{
			if (isNumberChar(InString.substring(Count-1,Count)))
				{OutString=OutString+"*"+TempChar}
			else OutString=OutString+TempChar
			}
	}
	return (OutString);
}


function reverse (InString)  {
	OutString="";
	var Length = InString.length;
	for (Count=Length; Count > -1; Count--)  {
		TempChar=InString.substring (Count, Count+1);
		if (TempChar == "(") {TempChar = ")"}
		else if  (TempChar == ")") {TempChar = "("}
		OutString=OutString+TempChar;
		}
	return (OutString);
	}

function powFix2(InString) {
	// ****Replaces one "^" by "pow"

	theString = InString;
	var Length = theString.length;
	outString = theString; 
		// in case nothing happens
	
		// Look for wedge
	var looking = true;
	for (Count=0; Count < Length; Count++)  
		{
		if (looking)
			{
			TempChar=theString.substring (Count, Count+1);
			if (TempChar == "^")
				{
				looking = false;
				rightStr = theString.substring (Count+1,Length);
				leftStr = theString.substring (0,Count);
				// deal with right-hand string
				Aray = breakApart(rightStr);
				Arg2 = Aray[1];
				rightRest = Aray[2];
			
				backString = reverse(leftStr);
				Aray = breakApart(backString);
				Arg1 = reverse(Aray[1]);
				leftRest = reverse(Aray[2]);
				outString = leftRest+"Math.pow("+Arg1+","+Arg2+")"+rightRest;
				
				} // end hif hit a wedge

			} // end of looking for a wedge
		} // end of loop

// ****** testing *******
// document.Extra.diagnostics.value += outString + cr;
// ***** end testing *****

return (outString);

} // end of powFix2

function powCheck(InString) {
	// ****checks for ^
	
	theString = InString;
	var Length = theString.length;
	
	// Look for wedge
	var found = false;
	for (Count=0; Count < Length; Count++)  
		{
		TempChar=theString.substring (Count, Count+1);
		if (TempChar == "^")
			{
			found = true;
			} // end if hit a wedge
		} // end of looking for a wedge
	return(found);


} // end of powCheck

function myParse(expression)
{
		var theString = stripSpaces(expression);		
		with (Math)
			{
		// now convert formatting from GC formatting		
		theString = putProduct(theString);
		theString = replaceSubstring(theString,"log","(1/Math.log(10))*Math.log");
		theString = replaceSubstring(theString,"ln","Math.log");
		theString = replaceSubstring(theString,"abs","Math.abs");
			while (powCheck(theString))
				{
				theString = powFix2(theString);
				// alert (theString);
				}
		theString = replaceChar(theString,"X","x");
			} // with Math
	return(theString);
} // myParse
// ******** END FUNCTION PARSER **************





// ********* Answer checking routines *********
// the following two routines are can be used in both tutorials and 
// review exercises to do answer checking and "peeking"
// handles both strings and numerical values.

// These routines use one or two other string utilities in this file
// example of html code that uses this:
// 
// <form name = "Form1">
//  <input type=text size=35 value="" name="Q1a">
// <input type="button" value = "Verifica" onClick = 
// "if (checkAnswer('Form1','Q1a',3,3.1419)) winopen('correct.html','bottom'); 
// else winopen('wrong.html','bottom') ">
// <input type="button" value = "Vistazo" onClick="togglePeek('Form1','Q1a', '3.1419')">
//


function checkAnswerandValue(formName,fieldName,correctAnswer,minLength, maxLength, maxTolerance, assig1,assig2,assig3, assig4) {
// use this to check for simplified expressions
// evaluates the input string in the specified form 
// & returns 1 if the answer is correct (agrees with correctAnswer)
// to within 0.00005 and is the right length otherwise set "maxerror" = whatever
// as one of the assignments
// returns 2 if the answer is right but string too long (unsimplified)
// returns 3 if answer is right but string too short 
// returns 0 if the answer is blank 
// else returns 6;
// it evalutes the input string at sthe specified values 
// Each assigi has the form "x=2" or "h=2.3" 
// minLength & maxLength are the permissable ranges of an input string\
// maxTolerance is the largest possible error
// NOTE: requires GLOBAL variables x, h, or whatever is assigned
if (0 == 1) return(1);
else {
var theString = "";
var maxerror = maxTolerance; 	
var a1 = eval("theString = stripSpaces(document."+ formName + "." + fieldName + ".value"+")" );
theString = stripChar(theString, ">");
if (assig1 != "") var b1 = eval(assig1);  // set the values equal to numbers
if (assig2 != "") var b2 = eval(assig2);
if (assig3 != "") var b3 = eval(assig3);
if (assig4 != "") var b4 = eval(assig4);

if (theString == "") return(0);

else {
	theString = stripChar (theString, "$");		// for dollar signs
	theString = stripChar (theString, ",");		// for longer numbers
	theString = theString.toLowerCase();
	try
		{
 		var trialval = myEval (theString);
		}
	catch (error)
		{
 		 return(6);
		}
	var val = myEval (theString);
	var correctVal = myEval(correctAnswer);
	var err = Math.abs(val - correctVal);
	if (err < maxerror)
		{
		if (theString.length > maxLength) return(2);
		else if  (theString.length < minLength) return(3);
		else return(1);
		}
	else return (6);
	} // endif non-empty
} // if 0 is not equal to 1
} // end checkAnswerandValue




function togglePeek(formName,fieldName,expression) {
// displays the given expression in formName.fieldname if not already visible
// if already visible, it hides it

var theCommand = "";
var theString = "if (document." + formName + "." + fieldName + ".value != '" + expression + "') document." + formName + "." + fieldName + ".value = '" + expression + "';  else document." + formName + "." + fieldName + ".value = '';"
// alert(theString)
var act1 = eval(theString);
return(true);
}

// ************** end of answer handling routines *************


