
function putProduct(InString) {
// just for number times paren or times variable
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 myEval(theString)
{
theString = replaceSubstring (theString,"cos","Math.cos");
theString = replaceSubstring (theString,"sin","Math.sin");
theString = replaceSubstring (theString,")(",")*(");
theString = replaceSubstring (theString,"x(","x*(");
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))
}


// ********* FUNCTION PARSER ***********

// 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 **************


// ************ Exercise generator ************************

function formatPoly(theInputmatrix, negExponents,rationalExponents,asRadicals) {
// if negExponents is true then perits them else puts them in demonimator when the coefficients are rational or integer
// alert("hello");

var theCoeffMatrix = theInputmatrix[2];
// alert(theInputmatrix[1]);
// coeffType 1: integer; 2: fraction; 3: decimal
// takes a matrix of coefficients and returns an array
// [0] entry is the polynomial as a javascript expression
// [1] entry is the html in <td> tags
// [2] is the coefficient matrix that was input

var degree = theCoeffMatrix[100];
var coeffType = theCoeffMatrix[101];
var variableName = theCoeffMatrix[102];
var negDegree = theCoeffMatrix[103];
var theJscriptString = '', theTdString = '';
var theOutput = ['',''];
var theCoeff = '';
var theTdCoeffArray = new Array();
var n = degree;
var varName = variableName;
var exponStr = ''; // will be exponent string
var absExponStr = ''; // abs value of above
var exponJStr = ''; 
	// will be exponent string for Javascript (parens around exponents)
var absExponJStr = ''; // abs value of above

if (!(negExponents)&&(coeffType == 1)) coeffType = 2; 

// now integer coeficients
if ((coeffType == 1) || (coeffType == 3)) { 
	theTdString += '<td>'
	for (var i = n; i >= 0; i--) {
		var I = i - negDegree; // I = actual exponent 
		if (rationalExponents) {
			var theFrac = toFrac(I);
			exponStr = toFrac(I)[3];
			absExponStr = toFrac(Math.abs(I))[3];
			if (theFrac [4] == 0) { 
				exponJStr = exponStr;
				absExponJStr = absExponStr
				}
			else {
				exponJStr = "(" + exponStr + ")";
				absExponJStr = "(" + absExponStr + ")"
				}
			} // rationalExponents
		else {
			exponStr = roundSigDig(I,5);
			absExponStr = roundSigDig(Math.abs(I),5);
			exponJStr = exponStr;
			absExponJStr = absExponStr;
			}

		theCoeff  = parseFloat(theCoeffMatrix[Math.floor(i)]);
		if ((theCoeff > 0)&&(theJscriptString != '')) {
			theTdString += ' + ';
			theJscriptString += ' + ';
			}
		else if (theCoeff < 0) {
			if (theJscriptString != '') theTdString += ' <font face = ' + quoteMark + 'Courier' + quoteMark + '>-</font> ';
				else theTdString += '<font face = ' + quoteMark + 'Courier' + quoteMark + '>-</font>';
			if (theJscriptString == '') theJscriptString += '-';
			else theJscriptString += ' - ';
			theCoeff = - theCoeff;
			}
		
		
		if (theCoeff != 0) {
			if ((Math.abs(theCoeff) != 1)||(I == 0)) {
				theTdString += roundDec(theCoeff,4);
				theJscriptString += roundDec(theCoeff,4);
				}
			if (I == 1) {
				theTdString += '<font class = math>' + varName + '</font>';
				if (theCoeff == 1) theJscriptString += 'x';
				else theJscriptString += 'x';
				} // degree = 1
			else if (I != 0) {
				theTdString += '<font class = math>' + varName  + '</font><sup>' + exponStr + '</sup>';
				if (theCoeff == 1) theJscriptString += 'x^' + exponJStr;
				else theJscriptString += 'x^' + exponJStr;
				} // degree > 0
			} // if nonzero coeff
		
		} // i
	theTdString += '</td>'
	} // if integer

// now rational coefficients
else if (coeffType == 2) { 
	var theCoeffN = 0, theCoeffD = 1;
	for (var i = n; i >=0; i--) {
		var I = i - negDegree; // I = actual exponent
		if (rationalExponents) {
			var theFrac = toFrac(I);
			exponStr = toFrac(I)[3];
			absExponStr = toFrac(Math.abs(I))[3];
			if (theFrac [4] == 0) { 
				exponJStr = exponStr;
				absExponJStr = absExponStr
				}
			else {
				exponJStr = "(" + exponStr + ")";
				absExponJStr = "(" + absExponStr + ")"
				}
			} // rationalExponents
		else {
			exponStr = roundSigDig(I,5);
			absExponStr = roundSigDig(Math.abs(I),5);
			exponJStr = exponStr;
			absExponJStr = absExponStr;
			}

		theCoeff  = parseFloat(theCoeffMatrix[Math.floor(i)]);
// alert("degree =" +i + " coeff =" + theCoeff);
		var theFrac = toFrac(theCoeff,biggestDenom);
		theCoeffN = theFrac[1]; theCoeffD = theFrac[2];
		if ((theCoeffN > 0)&&(theJscriptString != '')) {
			theTdString += '<td>+</td> ';
			theJscriptString += ' + ';
			}
		else if (theCoeffN < 0) {
			if (theJscriptString != '') theTdString += '<td><font face = ' + quoteMark + 'Courier' + quoteMark + '>-</font></td>';
				else theTdString += '<td><font face = ' + quoteMark + 'Courier' + quoteMark + '>-</font></td>';
			if (theJscriptString == '') theJscriptString += '-';
			else theJscriptString += ' - ';
			theCoeffN = - theCoeffN;
			}
		if (theCoeffN != 0) {

			if ((I < 0) && !(negExponents)) {
				if (theCoeffD == 1) {
					if  (!(I == -1)) {
						theTdString += '<td nowrap><center>' + theCoeffN + '<br><img src = ' + quoteMark + 'SYMB/FR.GIF' + quoteMark + ' height = 1 width =100%><br><font class = math>' + varName + '</font><sup>'+ absExponStr + '</sup></center></td>';
						theJscriptString += theCoeffN + '/x^'+ absExponJStr;
						}
					else {
						theTdString += '<td nowrap><center>' + theCoeffN + '<br><img src = ' + quoteMark + 'SYMB/FR.GIF' + quoteMark + ' height = 1 width =100%><br><font class = math>' + varName + '</font></center></td>';
						theJscriptString += theCoeffN + '/x';
						}
					}
				else {
					if  (!(I == -1)) {
						theTdString += '<td nowrap><center>' + theCoeffN + '<br><img src = ' + quoteMark + 'SYMB/FR.GIF' + quoteMark + ' height = 1 width =100%><br>' + theCoeffD + '<font class = math>' + varName + '</font><sup>'+ absExponStr + '</sup></center></td>';
						theJscriptString += theCoeffN + '/(' + theCoeffD + 'x^'+ absExponJStr + ')';
								}
					else {theTdString += '<td nowrap><center>' + theCoeffN + '<br><img src = ' + quoteMark + 'SYMB/FR.GIF' + quoteMark + ' height = 1 width =100%><br>' + theCoeffD + '<font class = math>' + varName + '</font></center></td>';
					theJscriptString += theCoeffN + '/(' + theCoeffD + 'x)';
					}
					}

			} 
			else if ((theCoeffD != 1)&&(theCoeffN != 1)) {
				if ( !(I == 1) && !(I == 0)) {
					theTdString += '<td nowrap><center>' + theCoeffN + '<font class = math>' + varName + '</font><sup>'+ exponStr + '</sup><br><img src = ' + quoteMark + 'SYMB/FR.GIF' + quoteMark + ' height = 1 width =100%><br>' + theCoeffD + '</center></td>';
					theJscriptString += theCoeffN + 'x^'+ exponJStr +'/' + theCoeffD;
					}
				else if (I == 1) {
					theTdString += '<td nowrap><center>' + theCoeffN + '<font class = math>' + varName + '</font><br><img src = ' + quoteMark + 'SYMB/FR.GIF' + quoteMark + ' height = 1 width =100%><br>' + theCoeffD + '</center></td>';
					theJscriptString += theCoeffN + 'x/' + theCoeffD;
					} // degree = 1
				else if (I == 0) {
					theTdString += '<td nowrap><center>' + theCoeffN + '<br><img src = ' + quoteMark + 'SYMB/FR.GIF' + quoteMark + ' height = 1 width =100%><br>' + theCoeffD + '</center></td>';
				theJscriptString += theCoeffN + '/' + theCoeffD;
				} // degree = 0
			} // if none-1 coeff
		else if ((theCoeffD != 1)&&(theCoeffN == 1)) {
				if ( !(I == 1) && !(I == 0)) {
					theTdString += '<td nowrap><center><font class = math>' + varName + '</font><sup>'+ exponStr + '</sup><br><img src = ' + quoteMark + 'SYMB/FR.GIF' + quoteMark + ' height = 1 width =100%><br>' + theCoeffD + '</center></td>';
					theJscriptString += 'x^'+ exponJStr +'/' + theCoeffD;
					}
				else if (I == 1) {
					theTdString += '<td nowrap><center><font class = math>' + varName + '</font><br><img src = ' + quoteMark + 'SYMB/FR.GIF' + quoteMark + ' height = 1 width =100%><br>' + theCoeffD + '</center></td>';
					theJscriptString += 'x/' + theCoeffD;
					} // degree = 1
				else if (I == 0) {
					theTdString += '<td nowrap><center>1<br><img src = ' + quoteMark + 'SYMB/FR.GIF' + quoteMark + ' height = 1 width =100%><br>' + theCoeffD + '</center></td>';
				theJscriptString += '1/' + theCoeffD;
				} // degree = 0
			} // if numerator is 1
		else if ((theCoeffD == 1)&&(theCoeffN != 1)) {
				if ( !(I == 1) && !(I == 0)) {
					theTdString += '<td nowrap><center>'+ theCoeffN + '<font class = math>' + varName + '</font><sup>'+ exponStr + '</sup></center></td>';
					theJscriptString += theCoeffN + 'x^'+ exponJStr;
					}
				else if (I == 1) {
					theTdString += '<td nowrap><center>'+ theCoeffN + '<font class = math>' + varName + '</font></center></td>';
					theJscriptString += theCoeffN + 'x';
					} // degree = 1
				else if (I == 0) {
					theTdString += '<td nowrap><center>' + theCoeffN + '</center></td>';
				theJscriptString += theCoeffN;
				} // degree = 0
			} // if only denom is 1
		else if ((theCoeffD == 1)&&(theCoeffN == 1)) {
				if ( !(I == 1) && !(I == 0)) {
					theTdString += '<td nowrap><center><font class = math>' + varName + '</font><sup>'+ exponStr + '</sup></center></td>';
					theJscriptString += 'x^'+ exponJStr;
					}
				else if (I == 1) {
					theTdString += '<td nowrap><center><font class = math>' + varName + '</font></center></td>';
					theJscriptString += 'x';
					} // degree = 1
				else if (I == 0) {
					theTdString += '<td nowrap><center>1</center></td>';
				theJscriptString += 1;
				} // degree = 0
			} // if only denom is 1

		} // if non-zero fraction
	
		
		} // i
	theTdString += '</td>'
	} // if fraction 

if (theJscriptString == '') {theJscriptString = "0"; theTdString = "<td>0</td>"}
if (asRadicals) theTdString = convertToRadicals(theTdString);
theOutput[0] = theJscriptString;
theOutput[1] = theTdString;
theOutput[2] = theCoeffMatrix;

return(theOutput);
	
} // formatPoly


function convertToRadicals(theSt) {
// only does square roots at the moment.
var theRadStr = radicalString("<font class = math>x</font>");
theSt = replaceSubstring(theSt,"<font class = math>x</font><sup>1/2</sup>", theRadStr, false);
theSt = replaceSubstring(theSt,"<font class = math>x</font><sup>3/2</sup>", "<font class = math>x</font>"+theRadStr, false);

theSt = replaceSubstring(theSt,"<font class = math>x</font><sup>5/2</sup>", "<font class = math>x</font><sup>2</sup>"+theRadStr, false);
return (theSt);


} // convertToRadicals


function formatQuotient(theInput, negExponents,rationalExponents,asRadicals) {
var theNumerator = theInput[2];
var theDenominator = theInput[3];
// alert(theNumerator[1]);
var theOutputN = formatPoly(theNumerator, negExponents,rationalExponents,asRadicals);
var theOutputD = formatPoly(theDenominator, negExponents,rationalExponents,asRadicals);
var theOutput = new Array();
theOutput[0] = '(' + theOutputN[0] + ')/(' +  theOutputD[0] + ')';
theOutput[1] = '<td nowrap><center><table><tr>' + theOutputN[1] + '</tr></table><img src = "SYMB/FR.GIF" height = 1 width =100%><table><tr>' + theOutputD[1] + '</tr></table></center></td>';
return(theOutput);
} // formatQuotietn

function pickALetter() {
	var theNum = Math.round(4*Math.random());
	var varName = '';
	if (theNum == 0) varName = 'x';
	else if (theNum == 1) varName = 't';
	else if (theNum == 2) varName = 's';
	else if (theNum == 3) varName = 'p';
	else varName = 'q';
	return(varName);
} // pickALetter



function createPoly(degree, shift, coeffType, variableName, complexity) {
// coeffType 1: integer; 2: fraction; 3: decimal
// variableName "x", "t" etc or "random"
// complexity integer part = 0, 1, 2, 3, 4, 5 effects number of sig digits in decimals and size of denominators in fractions
// the decimal value of complexity = max number of terms (up to 3)
// eg complexity 3.2 gives a complexity 3 poly with up to 2 terms
// degree must be positive 
// shift is subtracted from the degree 
// this is stored in 103 entry and nothing more in create
// eg degree 2.3 starts at x^(3-2) and descends
// complexity = 0 gives a monic as well and is otherwise same as complexity 1
// returns an array [0] term is 0 (depth of this structure)
// [1] term = "P" for polynomial
// [2] term is a coefficient matrix whose [i] term is the
// coeff of x^i. The [100] term is the degree and [101] the
// coefficient type
// the [103] term is the exponent negative shift
var monic = false;
var numTerms = 0;
var maxNumTerms = Math.round(10*(complexity - Math.floor(complexity)));
if (maxNumTerms == 0) maxNumTerms = 666; // none specified
// alert(maxNumTerms);
complexity = Math.floor(complexity);
var negDegree = shift;
var n = Math.floor(degree); // positive degree
if (complexity == 0) {monic = true; complexity = 1}
var theCoeffMatrix = new Array();
var theOuputmatrix = new Array();
theCoeffMatrix[100] = degree;
theCoeffMatrix[101] = coeffType;
var varName = variableName;
if (variableName == 'random') varName = pickALetter();
theCoeffMatrix[102] = varName;
theCoeffMatrix[103] = negDegree;
// now integer coeficients
if (coeffType == 1) { 
		var theCoeff = 0;
		for (var i = n; i >= 0; i--) {
			if (numTerms < maxNumTerms) {
				var maxInteger = Math.pow(6,complexity);
				theCoeff = Math.round(maxInteger*Math.random()-maxInteger/2);
				while ( (i == n) && theCoeff == 0) theCoeff = Math.round(maxInteger*Math.random()-maxInteger/2); 
				} // if not exceeded maxNumTerms
			else theCoeff= 0;
				theCoeffMatrix[i] = theCoeff;
			if (theCoeff!= 0) numTerms += 1;
			} // i
		} // if integer

// now rational coefficients
else if (coeffType == 2) { 
	var theCoeffN = 0, theCoeffD = 1;
	for (var i = n; i >= 0; i--) {
		if (numTerms < maxNumTerms) {
			var maxInteger = Math.pow(6,complexity);
			theCoeffN = Math.round(maxInteger*Math.random()-maxInteger/2);
			while ( (i == n) && theCoeffN == 0) theCoeffN = Math.round(maxInteger*Math.random()-maxInteger/2);
		 	theCoeffD = Math.round(maxInteger*Math.random()-maxInteger/2);
			while (theCoeffD == 0) theCoeffD = Math.round(maxInteger*Math.random()-maxInteger/2);
		// must have a  non-zero coefficient to start and non-zero denominators
			} // if not exceeded maxNumTerms
		else {theCoeffN = 0; theCoeffD = 1}
		theCoeffMatrix[i] = theCoeffN/theCoeffD; 

		if (theCoeffN != 0) numTerms += 1;
		} // i
	} // if fraction 
// now decimal coefficients
else if (coeffType == 3) { 
	var theCoeff = 0; 
	var maxNumber = Math.pow(6,complexity);
	var c1 = 0, roundToThis = 0;
	for (var i = n; i >= 0; i--) {
		if (numTerms < maxNumTerms) {
			c1 = maxNumber*Math.random()-maxNumber/2;
			roundToThis = Math.round(complexity/2);
			theCoeff = roundDec(c1,roundToThis);
			while ( (i == n) && theCoeff == 0) {
				c1 = maxNumber*Math.random()-maxNumber/2;
				roundToThis = Math.round(complexity/2)+1;
				theCoeff = roundSigDig(c1,roundToThis);
				} // LEADING COEFF
			} // if not exceeded maxNumTerms
		else theCoeff = 0;
		theCoeffMatrix[i] = theCoeff;
		if (theCoeff != 0) numTerms += 1;
		} // i
	} // if decimal
if(monic) theCoeffMatrix[n] = 1;
theOuputmatrix[0] = 0;
theOuputmatrix[1] = "P";
theOuputmatrix[2] = theCoeffMatrix;
return(theOuputmatrix);
	

} // createPoly


function createRational(degreeN, shiftN, degreeD, shiftD, coeffType, variableName, complexity) {
// outputs:
// [0] entry is the polynomial as a javascript expression
// [1] entry is the html in <td> tags
// [2] is an array with [2] and [3] entries the numerator 
// and denominator coefficient matrices
// the [1] component is "Q" telling us that this is a rational function
// the [0] component is the depth of the structure
// Note that the denominator degree should not be zero --
//  because such things are technically not proper rational functions
var theNumerator = createPoly(degreeN, shiftN, coeffType, variableName, complexity);
var theNArray = theNumerator[2];
// denominator must have the same variable name..
variableName = theNArray[102];
var theDenominator = createPoly(degreeD, shiftD, coeffType, variableName, complexity);


var theOutput = new Array();
theOutput[0] = 1; // a level zero structure
theOutput[1] = 'Q';
theOutput[2] = theNumerator;
theOutput[3] = theDenominator;
return(theOutput);
} // createRational


function createPower(inputExpression,exponent, exponentType) {
// Output: [0] term is the depth of the structure
// [1] term = "E" for exponent
// [2] term is the entire structure being exponentiated
// [3] is the exponent
// [4] is the exponent type: 1: integer; 2: fraction; 3: decimal
var outputArray = new Array();
outputArray[0] = inputExpression[0] + 1;
outputArray[1] = "E"; 
outputArray[2] = inputExpression;
outputArray[3] = exponent;
outputArray[4] = exponentType;
return(outputArray);
} // power

function createQuotient(numerator, denominator) {
// Output: [0] term is the depth of the structure
// [1] term = "Q" for quotient
// [2] term is the entire structure in numerator
// [3] is the structure in the denominator
// [4] 
var outputArray = new Array();
outputArray[0] = inputExpression[0] + 1;
outputArray[1] = "Q"; 
outputArray[2] = numerator;
outputArray[3] = denominator;
return(outputArray);
} // createQuotient



function createPrimitiveSum (degree, shift, parameterType, variableName, complexity, primitiveFunctions) {
var usingNonpolyPrimitives = false;
	try
		{ 
 		var k = primitiveFunctions.length;
		if (k > 0) usingNonpolyPrimitives = true;
		}
	catch (error) 
		{ 
		k = 0;
		usingNonpolyPrimitives = false;
		}

if (usingNonpolyPrimitives) {
// special primitive structures:
var thePrimitivePart = [0,"sinx",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"primitive","y",];
var theTossUp = randomInt (0, 4);
var theChoice = randomInt(0,k-1);
var theChosenPrim = primitiveFunctions[theChoice];

thePrimitivePart[1] = primitiveFunctions[theChoice];
thePrimitivePart[104] = variableName;
// alert(thePrimitivePart);
if (theTossUp == 0) {
// alert("hello" + thePrimitivePart[1]);
	return(thePrimitivePart);
	}
else if (theTossUp == 1) {
	var thePoly = createPoly(degree, shift, parameterType, variableName, complexity);
	var theResult = new Array();
	theResult[0] = 1;
	theResult[1] = "S";
	theResult[2] = thePoly;
	theResult[3] = thePrimitivePart;
// alert(theResult[3]);
	var coinToss = randomInt(0,1);
	if (coinToss == 0) theResult[4] = "+";
	else theResult[4] = "-";
	theResult[104] = variableName;
	return(theResult);
	} // else
else if (theTossUp == 3) {
	// constant multiple
	var theCoeff = randomInt(2, 4);
	var flip = randomInt(0,1);
	if (flip == 1) theCoeff *= -1;
	var theResult = new Array();
	theResult[0] = 1;
	theResult[1] = "C";
	theResult[2] = theCoeff;
	theResult[3] = thePrimitivePart;
	theResult[104] = variableName;
	return(theResult);
	} // else

else return(createPoly(degree, shift, parameterType, variableName, complexity));
} // if usingNonpolyPrimitives

else return(createPoly(degree, shift, parameterType, variableName, complexity));

} // createPrimitiveSum


// the next function should go -- 
// however it is still used in the game for the difference quotient...
function createAndFormatRational(degreeN, degreeD, coeffType, variableName, complexity) {
// outputs:
// [0] entry is the polynomial as a javascript expression
// [1] entry is the html in <td> tags
// [2] is an array with [2] and [3] entries the numerator 
// and denominator coefficient matrices
// the [1] component is "F" telling us that this is a fraction
// the [0] component is the depth of the structure
// Note that the denominator degree should not be zero --
//  because such things are technically not proper rational functions
var theNumerator = createPoly(degreeN, 0, coeffType, variableName, complexity);
var theNArray = theNumerator[2];
// denominator must have the same variable name..
variableName = theNArray[102];
var theDenominator = createPoly(degreeD, 0, coeffType, variableName, complexity);
var theDArray = theDenominator[2];
var theOutputN = formatPoly(theNumerator);
var theOutputD = formatPoly(theDenominator);
var theOutput = new Array();
theOutput[0] = '(' + theOutputN[0] + ')/(' +  theOutputD[0] + ')';
theOutput[1] = '<td nowrap><center><table><tr>' + theOutputN[1] + '</tr></table><img src = "SYMB/FR.GIF" height = 1 width =100%><table><tr>' + theOutputD[1] + '</tr></table></center></td>';
theOutput[2] = new Array();
theOutput[2][0] = 0; // depth 0 here
theOutput[2][1] = "F";
theOutput[2][2] = theNArray;
theOutput[2][3] = theDArray;
return(theOutput);
} // createandFormatRational


function createExpression2(operatorStr, theDepth, complexity, parameterType, exponentType, variableName, randomizingOperators, primitiveFunctions) {
// primitiveFuntions is an array of things like x^, ln, sin, 
// permitted for use instead of polynomials
// alert('here');
// creates an expression involving the operations permitted in theStr
// letters in the str are E,F,etc indicating the type of expressions permitted
// E = exponments, Q = quotients T = product, S = sum/difference, R = radical, N = sine, C = constant multiple
// parameterType & exponentType = integerl rational or decimal as usual

var theCurrentStructure = new Array();
if (variableName == 'random') variableName = pickALetter(); // fix the variable
var l = operatorStr.length;
var theChoiceNum = 0, theChoice = '';
var usingNonpolyPrimitives = false;
	try
		{ 
 		var prr = primitiveFunctions.toString();
		if (prr != '') usingNonpolyPrimitives = true;
		}
	catch (error) 
		{ 
		}

if (theDepth == 0) {
	var theTossup = randomInt(0, 1);
// alert(theTossup);
	var degree = Math.round(complexity/2) + Math.round(2*Math.random());
	if (degree == 0) degree = 1;
	if ((!usingNonpolyPrimitives)|| (theTossup == 0 )) return(createPoly(degree, 0, parameterType, variableName, complexity));
	else return (createPrimitiveSum(degree, 0, parameterType, variableName, complexity , primitiveFunctions));
	}
else {
	for (var i = 1; i <= theDepth; i++) {
	if(randomizingOperators) {
			theChoiceNum = Math.round((l-1)*Math.random());
			theChoice = operatorStr.charAt(theChoiceNum);
			}
	else theChoice = operatorStr.charAt(i-1);

// alert(theChoice);
	if (theChoice == "E") {
		var theStructure = new Array();
		theStructure[0] = i-1; // depth
		theStructure[1] = "E";
		if (i == 1) {
			// must construct the inside here
			var degree = Math.round(complexity/2) + Math.round(2*Math.random());
			if (degree == 0) degree = 1; // inside should not be a constant
			theStructure[2] = createPrimitiveSum (degree, 0, parameterType, variableName, complexity, primitiveFunctions);
			
			}
		else theStructure[2] = theCurrentStructure;
		if (exponentType == 1) {
			var exponent = Math.round(Math.random()*2*complexity - complexity);
			if (exponent == 0) exponent = 2;
			else if((exponent == 1)||(exponent == -1)) exponent *= 2;
			theStructure[3] = exponent;
			} // integer exponent
		else if (exponentType == 2) {
			var exponentN = Math.round(Math.random()*2*complexity - complexity);
			if (exponentN == 0) exponentN = Math.round(Math.random(3*complexity)+1);
			var exponentD = Math.round(2*Math.random()*complexity);
			if (exponentD == 0) exponentD = Math.round(Math.random(3*complexity)+1);
			else if ((exponentD == 1)||( exponentD == -1)) exponentD *= 2;
			if (exponentN/exponentD == 1) exponentD += Math.round(Math.random(3*complexity)+1);
			theStructure[3] = exponentN/exponentD;
			} // rational exponent
			else if (exponentType == 3) {
			var decPlaces = Math.round(Math.pow(6,complexity));
			var exponent = roundDec(Math.random()*2*complexity - complexity,decPlaces);
			if (exponent == 0) exponentN += 2.3 + math.round(3*Math.random()-4);
			theStructure[3] = exponent;
			} // real exponent
		theStructure[4] = exponentType;
		theCurrentStructure = theStructure;
		} // exponent

	else if (theChoice == "C") {
		// constant multiple
		var theCoeff = randomInt(2, 4);
		var flip = randomInt(0,1);
		if (flip == 1) theCoeff *= -1;
		var theResult = new Array();
		theResult[0] = 1;
		theResult[1] = "C";
		theResult[2] = theCoeff;
		if (i == 1) {
			degree = Math.round(complexity/2);
			theResult[3] = createPrimitiveSum (degree, 0, parameterType, variableName, complexity, primitiveFunctions)
			} // 
		else {
			// decide on the depth of the second expression
			var theTempDepth = Math.round(Math.random()*(i-2));
			theResult[3] = createExpression2(operatorStr, theTempDepth, complexity/3, parameterType, exponentType, variableName, randomizingOperators, primitiveFunctions);
		return(theResult);

			} 
		} // constant multiple
	else if (theChoice == "Q") {
		var theStructure = new Array();
		if (i == 1) {
			//just generate a rational function
			var degreeN = Math.round(complexity/2) + Math.round(Math.random());
			var degreeD = 0; 
			degreeD = Math.round(complexity/2);
			if (degreeD == 0) degreeD = 1;
			// now increase the exponent using shifts
			if (complexity == 1) {
				degreeN += randomInt(0, 3);
				degreeD += randomInt(0, 3);
				}
			else {
				degreeN += randomInt(0, 3*complexity) + randomInt(1,3*complexity)/randomInt(1,3*complexity);
				degreeD += randomInt(0, 3*complexity) + randomInt(1,3*complexity)/randomInt(1,3*complexity);
				} 
			var shiftN = Math.floor(degreeN)-1;
			var shiftD = Math.floor(degreeD)-1;
			theStructure = createRational(degreeN, shiftN, degreeD, shiftD, parameterType, variableName, complexity + (complexity+1)/10);

			} // if first step
			else {
			theStructure[0] = i-1; // depth
			theStructure[1] = "Q";
			// decide whether the previous epxression should go in the numerator or denomiator
			var theDecision = Math.round(Math.random()); 
			var theTempDepth = Math.round(Math.random()*(i-2));
			if (theDecision == 0) {
				var degree = Math.round(complexity/2);
				theStructure[2] = createExpression2(operatorStr, theTempDepth, complexity/3, parameterType, exponentType, variableName);
				theStructure[3] = theCurrentStructure;
				} // old expression in the denominator
			else {
				var degree = Math.round(complexity/2);
				if (degree == 0) degree = 1;
				theStructure[3] = createExpression2(operatorStr, theTempDepth, complexity/3, parameterType, exponentType, variableName);
				theStructure[2] = theCurrentStructure;
				} // old expression in the numerator
			} // later step
		theCurrentStructure = theStructure;
		} // fraction
	else if (theChoice == "T") {
		// product (note that 'P' is reserved for polynomials
	
		var theStructure = new Array();
		theStructure[0] = i-1; // depth
		theStructure[1] = "T";
		if (i == 1) {
			//just generate a product of polynomials
			var degreeN = Math.round(complexity/2) + Math.round(Math.random());
			var degreeD = Math.round(complexity/2) + Math.round(Math.random());
			theStructure[2] = createPrimitiveSum (degreeN, 0, parameterType, variableName, complexity, primitiveFunctions);
			theStructure[3] = createPrimitiveSum (degreeD, 0, parameterType, variableName, complexity, primitiveFunctions);
// alert(theStructure[2]);
// alert(theStructure[3]);
			} // if first step
			else {
			// decide whether the previous epxression should go in the numerator or denomiator
			var theTempDepth = Math.round(Math.random()*(i-2));
			var theDecision = Math.round(Math.random()); 
			if (theDecision == 0) {
				var degree = Math.round(complexity/2) + Math.round(Math.random());
// alert("hello");
				theStructure[2] = createExpression2(operatorStr, theTempDepth, complexity/3, parameterType, exponentType, variableName);
				theStructure[3] = theCurrentStructure;
				} // old expression on the right
			else {
				var degree = Math.round(complexity/2) + Math.round(Math.random());
// alert("hello");
				theStructure[3] = createExpression2(operatorStr, theTempDepth, complexity/3, parameterType, exponentType, variableName);
				theStructure[2] = theCurrentStructure;
				} // old expression on the left
			} // later step
		theCurrentStructure = theStructure;
		} // product
	else if (theChoice == "S") {
		// sum or difference
		var isADifference = false;
		if (Math.random() > .5) isADifference = true;
		
		var theStructure = new Array();
		theStructure[0] = i-1; // depth
		theStructure[1] = "S";
		if (i == 1) {
			// A sum of polynomials would be silly
			// so do a difference instead
			var degreeN = Math.round(complexity/2) + Math.round(Math.random());
			var degreeD = Math.round(complexity/2) + Math.round(Math.random());
			if(degreeN == 0) degreeN = 1;
			if(degreeD == 0) degreeD = 1;
			theStructure[2] = createPoly(degreeN, 0, parameterType, variableName, complexity);
			theStructure[3] = createPoly(degreeD, 0, parameterType, variableName, complexity);
			theStructure[4] = '-'; // difference
			} // if first step
			else {
			if(isADifference) theStructure[4] = '-';
			else theStructure[4] = '+';

			// decide on the depth of the second expression
			var theTempDepth = Math.round(Math.random()*(i-2));
			// decide whether the previous epxression should go first or second
			var theDecision = Math.round(Math.random()); 
			if (theDecision == 0) {
				var degree = Math.round(complexity/2) + Math.round(Math.random());
				theStructure[2] = createExpression2(operatorStr, theTempDepth, complexity/3, parameterType, exponentType, variableName);
				theStructure[3] = theCurrentStructure;
				} // old expression on the right
			else {
				var degree = Math.round(complexity/2) + Math.round(Math.random());
				theStructure[3] = createExpression2(operatorStr, theTempDepth, complexity/3, parameterType, exponentType, variableName);
				theStructure[2] = theCurrentStructure;
				} // old expression on the left
			} // later step
		theCurrentStructure = theStructure;
		} // sum/difference

	} // i
return(simplify(theCurrentStructure));
} // if depth greater than zero
}


function simplify(structure) {
var outStructure = structure.slice(0);
// first convert minus a negative times something to plus
if(structure[1] == "S") {
	if ((structure[3][1] == "C") && (structure[3][2] < 0) && (structure[4] == "-")) {
		outStructure [3][2] *=-1;
		outStructure [4] = "+";
		} // minus negative
	// then convert plus a negative times something to minus
	if ((structure[3][1] == "C") && (structure[3][2] < 0) && (structure[4] == "+")) {
		outStructure [3][2] *=-1;
		outStructure [4] = "-";
		} // minus negative
	// next convert sine times sine to sin squared etc
	} // if a sum

return(outStructure);
} // simplify


function deriv(theStructure) {
var theResult = new Array();
if (theStructure [1] == 'P') return(polyDeriv(theStructure, 1));
else if (theStructure [1] == 'sinx'){
	theResult = theStructure.slice(0);
	theResult[1] = "cosx";		

	}

else if (theStructure [1] == 'cosx'){
	// 
	theResult = new Array();
	theResult[0] = 1;
	theResult[1] = "C"; // constant multiple
	theResult[2] = -1;	
	theResult[3] = theStructure.slice(0);
	theResult[3][1] = "sinx";

	}

else if (theStructure [1] == "C"){
	// constant multiple
	theResult = theStructure.slice(0);
	theResult[3] = deriv(theResult[3]);


	}

else if (theStructure [1] == 'S'){
	// product
	theResult = theStructure.slice(0);
	theResult[2] = deriv(theResult[2]);	
	theResult[3] = deriv(theResult[3]);	

	}

else if (theStructure [1] == 'T'){
	// product

	theResult[0] = theStructure [0] + 1; // depth increases
	theResult[1] = "S" ; // the new structure is a sum
	theResult[2] = theStructure.slice(0,103); // the original product-- will be modified
	theResult[3] = theStructure.slice(0,103);
	theResult[2][2] = deriv(theResult[2][2]); // deriv of first
	theResult[3][3] = deriv(theResult[3][3]); // deriv of second 
	theResult [4] = '+';

	}
else if (theStructure [1] == 'Q'){
	// product
	
	theResult[0] = theStructure [0] + 2; // depth increases
	theResult[1] = "Q" ; // the new structure is a quotient
	var theNumerator = new Array();
	theNumerator [0] = theStructure [0] + 1; // depth increases
	theNumerator [1] = "S" ; // the new structure is a sum
	theNumerator [2] = theStructure.slice(0,103); // the original product-- will be modified
	theNumerator [3] = theStructure.slice(0,103);
	theNumerator [2][1] = 'T';
	theNumerator [3][1] = 'T';
	theNumerator [2][2] = deriv(theNumerator [2][2]); // deriv of first
	theNumerator [3][3] = deriv(theNumerator [3][3]); // deriv of second 
	theNumerator [4] = '-';
	var theDenominator = new Array();
	theDenominator[0] = theStructure [0] + 1;
	theDenominator[1] = "E";
	theDenominator[2] = theNumerator [2][3];
	theDenominator[3] = 2;
	theResult[2] = theNumerator;
	theResult[3] = theDenominator;

	}
return(simplify(theResult));
}

function format(structure, negExponents,rationalExponents,asRadicals) {
// returns [0] = theJscriptString;
// [1] = theTdString inside <td> tags
if ((structure[0] == 0)&&(structure[1] == 'P')) return(formatPoly(structure, negExponents,rationalExponents,asRadicals));
else if ((structure[0] == 0)&&(structure[1] == 'Q')) 	{
// alert(structure[2][1]);
	return(formatQuotient(structure,negExponents,rationalExponents,asRadicals))
	}

else {
	if ((structure[1] == "sinx") || (structure[1] == "cosx")) {
		var theString = "<td>" + structure[1].substring(0,3) + "<font class = math>&nbsp;" + structure[104] + "</font></td>";
		var theJscriptString = structure[1].substring(0,3) + "(x)";
		var theOutput = new Array();
		theOutput[0] = theJscriptString;
		theOutput[1] = theString;
		return(theOutput);
		} // sine
	else if (structure[1] == "C") {
		var theFStr = "";
		var theJStr = '';
		var theConstSt = '';
		var theConstJSt = '';
		var parenflag = false;
		var theCoeff  = parseFloat(structure[2]);
		var negSign = ''; if ((theCoeff.toString()).charAt(0) == "-") negSign = "-";
		if((structure[3][1] == 'P')||(structure[3][1] == 'S')|| (structure[3][1] == 'C')) parenflag = true; // second factor needs to be bracketed

		if (rationalExponents) {
			if (Math.round(theCoeff) == theCoeff) {
				theConstJSt = Math.round(theCoeff).toString();
				if (theConstJSt == "1") theConstJSt = "";
				else if (theConstJSt == "-1") theConstJSt = "-";
				theConstSt = '<td>' + theConstJSt + '</td>';
				} // whole number
			else { 
				var theFrac = toFrac(theCoeff); 
				theConstJSt = theFrac[3];
				var theFracSt = '<td nowrap><center>' + Math.abs(theFrac [1]) + '<br><img src = "SYMB/FR.GIF" height = 1 width =100%><br>' + theFrac [2] + '</center></td>';
				if (parenflag) {
					theConstSt = '<td nowrap>(</td>' + theFracSt + '<td nowrap>)</td>'
					theConstJSt = '(' + theConstJSt + ')';
					}

				else if (negSign == "-") {
					theConstSt = '<td nowrap>(<font face = "Courier">-</font></td>' + theFracSt + '<td nowrap>)</td>';
					theConstJSt = '(' + theConstJSt + ')';
					}

				else theConstSt = theFracSt;
				} // denominator
				} // rationalExponents
		else {
			theConstJSt = roundSigDig(theCoeff,5);
			if ((theConstJSt < 0) || (parenflag)) {
				theConstJSt = "(" + theConstJSt + ")";
				theConstSt = "(" + theConstJSt + ")";
				}
			else theConstSt = theConstJSt;
			
			} 
		theFStr += theConstSt;
		if ((theConstJSt != "-")&&(theConstJSt != "") ) theConstJSt += "*";
		theJStr += theConstJSt;
		// now the main part
		var theExprr = format(structure[3], negExponents, rationalExponents, asRadicals);
// alert(theExprr);
		var theOutput = new Array();
		theOutput[0] = theJStr + theExprr[0];
		theOutput[1] = theFStr + theExprr[1];
		return(theOutput);
		} // constant multiple

	else if(structure[1] == "E") {
		// exponents
		var theString = '<TD><TABLE><TR><td class = "lb">&nbsp;</td><td><table><tr>';
		var theProcess = format(structure[2], negExponents,rationalExponents,asRadicals);
		theString += theProcess[1];
		theString += '</tr></table></td><td class = "rb">&nbsp;</td><td valign = top><font class = exp>';
		// now add the exponent
		var theExponent = eval(structure[3]);
		if (rationalExponents) {
			var theFrac = toFrac(theExponent);
			exponStr = theFrac [3];
			absExponStr = toFrac(Math.abs(theExponent))[3]
			if (theFrac [4] == 0) { 
				exponJStr = exponStr;
				absExponJStr = absExponStr
				}
			else {
				exponJStr = "(" + exponStr + ")";
				absExponJStr = "(" + absExponStr + ")"
				}
			} // rationalExponents 
		else {
			exponStr = theExponent;
			absExponJStr = theExponent
			}
		theString += exponStr +'<br>&nbsp;<br></font></td></TR></TABLE></TD>'
		var theOutput = new Array();
		theOutput[1] = theString;
		
		theOutput[0] = '(' + theProcess[0] + ')^' + absExponJStr;
		return(theOutput);
		} // exponents
		else if(structure[1] == "Q") {
		// quotient
		var parenflagN = false, parenflagD = false;
		var theString = '<td nowrap><center><table><tr>';
// alert(structure[2]);
		if(structure[2][1] == 'Q') parenflagN = true; // numerator is a quotient
		if(structure[3][1] == 'Q') parenflagD = true; // denomiator is a quotient
		var theNumFormat = format(structure[2] ,negExponents,rationalExponents,asRadicals);
		if (!parenflagN) theString += theNumFormat[1];
		else theString += '<td class = "lb">&nbsp;</td>' + theNumFormat[1] + '<td class = "rb">&nbsp;</td>';
		theString += '</tr></table><img src = "SYMB/FR.GIF" height = 1 width =100%><table><tr>';
		var theDenFormat = format(structure[3] ,negExponents,rationalExponents,asRadicals);
		if (!parenflagD) theString += theDenFormat[1];
		else theString += '<td class = "lb">&nbsp;</td>' + theDenFormat[1] + '<td class = "rb">&nbsp;</td>';
		theString += '</tr></table></center></td>';
		var theOutput = new Array();
		theOutput[1] = theString;
		// now test to see if parentheses are needed indenominator
		var testSt1 = '[' + theNumFormat[0] + ']/(' + theDenFormat[0] + ')';
		var testSt2 = '[' + theNumFormat[0] + ']/' + theDenFormat[0];
		x = 0.123;
		if (myEval(testSt1) == myEval(testSt2)) theOutput[0] = testSt2;
		else theOutput[0] = testSt1;
		return(theOutput);
		} // quotient 
	else if(structure[1] == "T") {
		// product
		var parenflag = false, parenflagD = false;
		var theString = '<td nowrap><center><table><tr>';
		if((structure[2][1] == 'P')||(structure[2][1] == 'S') ||(structure[2][1] == 'C')) parenflagN = true; // first factor is a poly
		if((structure[3][1] == 'P')||(structure[3][1] == 'S')|| (structure[3][1] == 'C'))  parenflagD = true; // second factor is a poly

		
		var theNumFormat = format(structure[2], negExponents,rationalExponents,asRadicals);
		if (!parenflagN) theString += theNumFormat[1];
		else theString += '<TD><TABLE><TR><td class = "lb">&nbsp;</td>' + theNumFormat[1] + '<td class = "rb">&nbsp;</td></TR></TABLE></TD>';
		var theDenFormat = format(structure[3], negExponents,rationalExponents,asRadicals);
		if (!parenflagD) theString += theDenFormat[1];
		
		else theString += '<TD><TABLE><TR><td class = "lb">&nbsp;</td>' + theDenFormat[1] + '<td class = "rb">&nbsp;</td></TR></TABLE></TD>';
		theString += '</tr></table></center></td>';
		
		var theOutput = new Array();
		theOutput[1] = theString;
		// now test to see if parentheses are needed in Jscript
		var testSt1 = '(' + theNumFormat[0] + ')*(' + theDenFormat[0] + ')';
		if (theNumFormat[0] == '1') testSt1 = '(' + theDenFormat[0] + ')';
		else if (theNumFormat[0] == '-1') testSt1 = '-(' + theDenFormat[0] + ')';
		else if (looksLikeANumber(theNumFormat[0])) testSt1 = theNumFormat[0] + '*(' + theDenFormat[0] + ')';
		else if (looksLikeANumber(theDenFormat[0])) testSt1 = '(' + theNumFormat[0] + ')*' + theDenFormat[0];
		theOutput[0] = testSt1;
		return(theOutput);
		} // product

	else if(structure[1] == "S") {
		// sum/difference
		// first convert minus a negative times something to plus
		if ((structure[3][1] == "C") && (structure[3][2] < 0) && (structure[4] == "-")) {
			structure[3][2] *=-1;
			structure[4] = "+";
			} // minus negative
		// then convert plus a negative times something to minus
		if ((structure[3][1] == "C") && (structure[3][2] < 0) && (structure[4] == "+")) {
			structure[3][2] *=-1;
			structure[4] = "-";
			} // minus negative

		var parenflag = false, parenflagD = false;


		var theString = '<td nowrap><center><table><tr>';
		if((structure[3][1] == 'P')||(structure[3][1] == 'S')) parenflagD = true; // second factor is a poly or a sum
		var theNumFormat = format(structure[2], negExponents,rationalExponents,asRadicals);
		var theSign = '+';
		if(structure[4] == '-') theSign = '<font face = ' + quoteMark + 'Courier' + quoteMark + '>-</font>';
		theString += '<TD><TABLE><TR>' + theNumFormat[1] + '<td>' + theSign + '</td></TR></TABLE></TD>';

		var theDenFormat = format(structure[3], negExponents,rationalExponents,asRadicals);
		if ((structure[4] == '+') && (structure[3][1] == 'P') && (structure[3][2][0] > 0)) parenflagD = false;
		if (!parenflagD) theString += theDenFormat[1];
		else theString += '<TD><TABLE><TR><td class = "lb">&nbsp;</td>' + theDenFormat[1] + '<td class = "rb">&nbsp;</td></TR></TABLE></TD>';
		theString += '</tr></table></center></td>';
		var theOutput = new Array();
		theOutput[1] = theString;
		var outJsStr = '';
		if (!parenflag) outJsStr = theNumFormat[0]; else outJsStr = '(' + theNumFormat[0] + ')';
		if (!parenflagD) outJsStr += structure[4] +   theDenFormat[0] ; else outJsStr += structure[4] + '(' + theDenFormat[0] + ')';
		outJsStr = replaceSubstring(outJsStr, "+-", "-");
		outJsStr = replaceSubstring(outJsStr, "--", "+");
		theOutput[0] = outJsStr;
		return(theOutput);
		} // product
	} // if a deeper level structure than 0

} // format structure

var theArray = new Array();
var theTest = true;

function doIt(degree, coeffType, variableName, complexity) {
theArray = createPoly(degree, 0, coeffType, variableName, complexity);
var theOutput = formatPoly(theArray);
return(theOutput);
}

function doIt2(derivativeOrder) {
var theOutput = formatPoly(polyDeriv(theArray,derivativeOrder));
return(theOutput);
} 


function polyDeriv(theInMatrix,order) {
// **** Accuracy Warning
// In decimal mode this rounds derivative coeffs to 10 decimal places
// and antiderivative coeffs to 5 places as defined in the following 
// two constants. (The deriv rounding is just to prevent suprious
// Jscript computation chopping errors.)
var theInputmatrix = theInMatrix.slice(0,103);
var theCoeffMatrix = theInputmatrix[2];
var derivAcc = 10;
var antiderivAcc = 5;
var negDegree = theCoeffMatrix[103];
var theDeriv = theInputmatrix;
if (order == 0) return(theDeriv);
else if (order > 0) {
	var theDerivCoeffs = new Array();
	theDerivCoeffs[100] = theCoeffMatrix[100];
	theDerivCoeffs[101] = theCoeffMatrix[101]; // coefftype
	theDerivCoeffs[102] = theCoeffMatrix[102]; // varname
	theDerivCoeffs[103] = theCoeffMatrix[103] + 1; 
// varname
	var deg = theCoeffMatrix[100];
	var n = Math.floor(deg);
	var decPart = deg - n;
//if(theTest) alert(order + '   ' + n);
	for (var i = 0; i <= n; i++) {
		if (theDerivCoeffs[101] != 3) theDerivCoeffs[i] = (i + decPart - negDegree)*theCoeffMatrix[i];
		else theDerivCoeffs[i] = roundDec((i + decPart - negDegree)*theCoeffMatrix[i], derivAcc);
		} // i
	theDeriv[2] = theDerivCoeffs;
	return(polyDeriv(theDeriv,order-1));
	} // if positive order (derivative)
else {
	var theAderiv = theInputmatrix;
	var theAderivCoeffs = new Array();
	theAderivCoeffs[100] = theCoeffMatrix[100] + 1;
	if (theCoeffMatrix[101] == 1) theAderivCoeffs[101] = 2;
	else theAderivCoeffs[101] = theCoeffMatrix[101];
	theAderivCoeffs[102] = theCoeffMatrix[102];
	var n = theAderivCoeffs[100];
	theAderivCoeffs[0] = 0;
	for (var i = 1; i <= n; i++) {
		if (theAderivCoeffs[101] != 3) theAderivCoeffs[i] = theCoeffMatrix[i-1]/i;
		else theAderivCoeffs[i] = roundDec(theCoeffMatrix[i-1]/i,antiderivAcc);
		} // i
// if(theTest) alert(order+1 + '   ' + n);
// theTest = false;
	theAderiv[2] = theAderivCoeffs;
	return(polyDeriv(theAderiv,order+1));
	} // if negative order (antiderivative)
}

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


// ******* ends exercise generator

