/*********************************************************************************/
/**			copyright (c) PlanetCalc.com, 2009-2010			**/
/**		    	Planet Calc math functions			         */
/*********************************************************************************/
var PCM = ( typeof(PCM)=='object' )?PCM:function() {

//privates
function ParseNumber( v ) {
	if ( typeof(v)=="number" ) {
		return true;
	}
	var str = new String( PCM.getValue(v) );	
	var res = str.match(/^[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?$/)!=null;	
	return res;
}

function IsDefined( v ) {
	return typeof(v)!='undefined';
}

function __enum_Array() {
	var arr = [];
	var src = this.args
	for( var i=0;i<src.length;++i ) {
		arr[i] = src[i];
	}
	return arr;
}


function __enum_Scalar() {
	var res = [ ];
	if ( IsDefined(this.arg1) ) res[res.length] = this.arg1;
	if ( IsDefined(this.arg2) ) res[res.length] = this.arg2;
	if ( IsDefined(this.arg3) ) res[res.length] = this.arg3;
	return res;
}


function tryMultiplyDivision( arg1, arg2 ) {
	if ( PCM.getValue(arg1.arg2) == PCM.getValue(arg2) ) {
		return arg1.arg1;
	} 
	if ( PCM.isNumber(arg1.arg1) && PCM.isNumber(arg2) ) {
		return PCM.division( PCM.multiplication( [ arg1.arg1,arg2 ] ), arg1.arg2);
	}
}
function tryMultiply( arg1, arg2 ) {
	if ( PCM.isNumber( arg1 ) && PCM.isNumber( arg2 ) ) {
		return PCM.getNumber(arg1) * PCM.getNumber(arg2);
	}
	var v1 = PCM.getValue(arg1);
	var v2 = PCM.getValue(arg2);
	if (  v1== "0" || v2 == "0" ) {
		return 0;
	}
	if ( v1 == "1" ) {
		return arg2;
	}
	if ( v2 == "1" ) {
		return arg1;
	}
	if ( arg1 instanceof PCM.multiplication_fn && arg2 instanceof PCM.multiplication_fn ) {
		var arr1 = arg1.__enum();
		return PCM.multiplication( arr1.concat( arg2.__enum() ) );
	}
	if ( arg1 instanceof PCM.division_fn && arg2 instanceof PCM.division_fn ) {
		if ( PCM.getValue(arg1.arg1) == PCM.getValue(arg2.arg2) && PCM.getValue(arg2.arg1) == PCM.getValue(arg1.arg2) ) {
			return 1;
		} else if ( PCM.getValue(arg1.arg1) == PCM.getValue(arg2.arg2) ) {
			return PCM.division( arg2.arg1, arg1.arg2 );
		} else if ( PCM.getValue(arg1.arg2) == PCM.getValue(arg2.arg1) ) {
			return PCM.division( arg1.arg1, arg2.arg2 );
		} else {
			return PCM.division( PCM.multiplication( [arg1.arg1, arg2.arg1 ] ) , PCM.multiplication( [arg1.arg2, arg2.arg2] ) );
		}
	} else if ( arg1 instanceof PCM.power_fn && arg2 instanceof PCM.power_fn && PCM.getValue(arg1.arg1)==PCM.getValue(arg2.arg1) ) {
		return PCM.power( arg1.arg1, PCM.sum( [arg1.arg2, arg2.arg2] ) );
	} else if ( arg1 instanceof PCM.division_fn ) {
		return tryMultiplyDivision( arg1, arg2 );
	} else if ( arg2 instanceof PCM.sqrt_fn && arg1 instanceof PCM.sqrt_fn ) {
		return PCM.sqrt( PCM.multiplication( [arg1.arg1, arg2.arg1] ) );
	} else if ( arg2 instanceof PCM.division_fn ) {
		return tryMultiplyDivision( arg2, arg1 );
	} else if ( v1==v2 ) {
		return PCM.power(arg1,2);
	}
}


function GetOptionalParenTex( arg, needParen ) {
	var leftP = needParen?'\\left(':"";
	var rightP = needParen?'\\right)':"";
	return leftP+ PCM.getTeX(arg) + rightP;
}
function GetOptionalParenMath( arg, needParen ) {
	var leftP = needParen?'(':"";
	var rightP = needParen?')':"";
	return leftP+ PCM.getMath(arg) + rightP;
}
function GetMultiplierTeX( arg ) {
	return GetOptionalParenTex( arg, arg instanceof PCM.sum_fn || arg instanceof PCM.minus_fn);
}
function GetMultiplierMath( arg ) {
	return GetOptionalParenMath( arg, arg instanceof PCM.sum_fn || arg instanceof PCM.minus_fn);
}

function GetPowerBaseTeX( arg ) {
	return GetOptionalParenTex( arg, arg instanceof PCM.sum_fn || arg instanceof PCM.multiplication_fn || arg instanceof PCM.division_fn || arg instanceof PCM.minus_fn );
}
function GetPowerBaseMath( arg ) {
	return GetOptionalParenMath( arg, arg instanceof PCM.sum_fn || arg instanceof PCM.multiplication_fn || arg instanceof PCM.division_fn || arg instanceof PCM.minus_fn );
}


function complexityDescSort( a, b ) {
	return PCM.getComplexity(a)-PCM.getComplexity(b);
}

function SolveComplexDerivative( x , der ) {
	if ( PCM.isConstant(x) ) {
		return 0;
	} else if ( PCM.getValue(x)=='x') {
		return der;
	}
	return PCM.multiplication( [ der, new PCM.derivative_fn( x ) ] );
}

function initOneArgFunction( parent, x, name, func ) {
	parent.arg1 = x;
	parent.immediatepowersign = true;
	parent.name = name;
	parent.__enum = __enum_Scalar;
	parent.getValue = function () {
		return this.name + '(' + PCM.getValue(this.arg1) + ')';
	}
	parent.__clone = function( arr ) {
		return func( arr[0] );
	}
	parent.getTeX= function () {
		return '\\'+ this.name + '\\left(' + PCM.getTeX(this.arg1) + '\\right)';
	}
	parent.getMath= function () {
		return  this.name + '(' + PCM.getMath(this.arg1) + ')';
	}
}

function initUnknownFunctionTeX( parent ) {
	parent.getTeX= function () {
		return this.name + '\\left(' + PCM.getTeX(this.arg1) + '\\right)';
	}
}

function ParsingPrimitivesTranslator() {
	var me = this;
	this.__translate = function( result ) {
		if  ( result instanceof  PCI.resultString ) {
			return result.getValue();
		} 
		if  ( result instanceof  PCI.resultReference) {
			var f = me[result.__name];
			if ( f ) {
				var res = f(result.value);
				return res;
			}
		}
		throw "Could not translate: " + PCM.getValue( result );		
	}
	this["func"]= function ( result ) {
		var fn = PCM.getValue(result[0]);
		var child = me.__translate(result[2]);
		var funcs = { 
			"sin": new PCM.sin_fn(child), "cos": new PCM.cos_fn(child), 
			"tan": new PCM.tan_fn(child), "cot": new PCM.cot_fn(child), 
			"tg": new PCM.tan_fn(child), "ctg": new PCM.cot_fn(child), 
			"th": new PCM.tanh_fn(child), "cth": new PCM.coth_fn(child), 
			"tanh": new PCM.tanh_fn(child), "coth": new PCM.coth_fn(child), 
			"ch": new PCM.cosh_fn(child), "sh": new PCM.sinh_fn(child), 
			"cosh": new PCM.cosh_fn(child), "sinh": new PCM.sinh_fn(child), 
			"sec": new PCM.sec_fn(child), "cosec": new PCM.csc_fn(child), 
			"sech": new PCM.sech_fn(child), "csch": new PCM.csch_fn(child), 
			"sqrt":new PCM.sqrt_fn(child), "exp":new PCM.power_fn(PCM.exp(),child), 
			"ln":new PCM.ln_fn(child),	"lg":new PCM.lg_fn(child), "lb":new PCM.lb_fn(child),
			"arcsin": new PCM.arcsin_fn(child), "arccos": new PCM.arccos_fn(child), 
			"arctan": new PCM.arctan_fn(child), "arccot": new PCM.arccot_fn(child), 
			"arctg": new PCM.arctan_fn(child), "arcctg": new PCM.arccot_fn(child),
			"arcsec": new PCM.arcsec_fn(child), "arccosec": new PCM.arccosec_fn(child)
			,"abs": new PCM.abs_fn(child), "sgn": new PCM.sign_fn(child),"sign": new PCM.sign_fn(child)
		};
		if ( funcs[fn] ) {
			return funcs[fn];
		}
		return new PCM.function_fn( child, fn );
	}

	this["funcnum"]= function ( result ) {
			var fn = PCM.getValue(result[0]);
			var pwr = PCM.getNumber(result[1]);
			var translatedArg = me.__translate(result[3]);

			var funcs = { 
				"root": new PCM.root_fn(translatedArg,pwr)
				, "log": new PCM.logn_fn(translatedArg,pwr)
			};
			return funcs[fn];

	}

		
	this["factor"]= function ( result ) {
		var sign =( PCM.getValue(result[0]) == "-" )?-1:1;
		if ( sign==1 ) {
			return me.__translate( result[1] );
		}
		return PCM.minus( me.__translate( result[1] ) );
	}



	this["value"]= function ( result ) {
		switch( result.__name ) {
			case "func":
			case "pi":
			case "exponenta":
			case "variable":
			case "funcnum":
				return me.__translate( result );
			case "paren expression":
				return me.__translate( result.value[1] );
			case "unsigned numeric literal":
				return PCM.getNumber(result);
		}
		return PCM.getNumber(result); //constant
	}
	this["variable"]= function ( result ) {
		return new PCM.variable_fn();
	}
	this["pi"]= function ( result ) {
		return new PCM.pi_fn();
	}
	this["exponenta"]= function ( result ) {
		return PCM.exp();
	}

	this["power"]= function ( result ) {
		if ( result[1].length == 0 ) {
			return me.__translate( result[0] );
		} else {
			var arr=[];
			var others = result[1];
			for( var i=0;i<others.length;++i ) {
				arr[arr.length] = me.__translate(others[i][1]);
			}
			var pw = PCM.multiplication( arr );
			var bs = me.__translate(result[0]);
			var res= new PCM.power_fn( bs, pw );
			return res;
		}
	}
	this["product"]= function ( result ) {
		if ( result[1].length == 0  ) {
			return me.__translate( result[0] );
		} else {
			
			var mul=[ me.__translate(result[0]) ];
			var div= [];
			var childs = result[1];
			for( var i =0;i<childs.length;++i ) {
				var child = childs[i];
				if ( PCM.getValue(child[0]) == "*" ) {
					mul[mul.length] = me.__translate(child[1]);		
				} else if ( PCM.getValue(child[0]) == "/" ) {
					div[div.length] = me.__translate(child[1]);
				}
			}
			if ( div.length ) {
				var num = mul.length>1?new PCM.multiplication_fn( mul ):mul[0];
				var den = div.length>1?new PCM.multiplication_fn( div ):div[0];
				return new PCM.division_fn( num, den );
			}  else {
				if ( mul.length==1 ) {
					return mul[0];
				}
				return new PCM.multiplication_fn( mul );
			}
		}
			
	}

	this["sum"]= function ( result ) {
		if ( result[1].length == 0  ) {
			return me.__translate( result[0] );
		} else {
			var res = [ me.__translate( result[0] ) ] ;
			var childs = result[1];
			for( var i =0;i<childs.length;++i ) {
				var child = childs[i];
				res[ res.length ] = me.__translate( child[1] );
				if ( PCM.getValue(child[0]) == "-" ) {
					res[res.length-1] = new PCM.minus_fn( res[res.length-1] );
				}
			}
			if ( res.length == 1 ) {
				return res[0];
			}
			return new PCM.sum_fn( res );
		}
	}
	this["expression"]= function ( result ) {
		return me.__translate( result );
	}
};


//publics
return {

"isNumber" : function ( v ) {
	return typeof(v)=="number";
},

"isConstant" : function ( v ) {
	if ( typeof(v)=="string" || typeof(v)=="number" ) {
		return true;
	}	
	if ( v instanceof PCM.variable_fn ) {
		return false;
	}
	var childs = v.__enum();
	for( var i=0;i<childs.length;++i ) {
		if ( !PCM.isConstant( childs[i] ) ) {
			return false;
		}
	}
	return true;
},

"getNumber" : function ( arg ) {
	var t = typeof(arg);
	if ( t=='number') {
		return arg;
	} else if ( t=='string') {
		return Number(arg);
	}

	return Number(arg.getValue());
}

,"getValue" : function ( arg ) {
	var t = typeof(arg);
	if ( t=='number') {
		return new String(arg);
	} else if ( t=='string' || t=='undefined') {
		return arg;
	}
	return arg.getValue?arg.getValue():arg;
},

"getTeX" : function ( arg ) {
	var t = typeof(arg);
	if ( t=='number') {
		return new String(arg);
	} else if ( t=='string' || t=='undefined') {
		return arg;
	}
	return arg.getTeX?arg.getTeX():arg;
},

"getMath" : function ( arg ) {
	var t = typeof(arg);
	if ( t=='number') {
		return new String(arg);
	} else if ( t=='string' || t=='undefined') {
		return arg;
	}
	return arg.getMath?arg.getMath():arg;
},

"getComplexity": function ( v ) {
	var complexity = 1;
	var t = typeof(v);
	if ( t=="object" || v.__enum) {
		if ( v instanceof PCM.variable_fn ) {
			complexity+=3;
		} else {
			complexity +=1
			if ( v instanceof PCM.division_fn ) {
				complexity +=1
			}
			if ( v instanceof PCM.power_fn ) {
				if ( typeof(v)=="number" || (typeof(v)=="object"  && v.arg1 instanceof PCM.variable_fn) ) {
					complexity +=1;
				} else {
					complexity +=2;
				}
			}
			var childs = v.__enum();
			for( var i=0;i<childs.length;++i ) {
				complexity += PCM.getComplexity( childs[i] ); 
			}       	
		}
	} else if ( t=="number" ) {
		if ( v<0 ) {
			complexity+=1;
		} 
		if ( v!=Math.round(v) ) {
			complexity+=1;
		}
	}
	return complexity;
},

"getNod" : function ( a_, b_) {
	var a = a_<0?-a_:a_;
	var b = b_<0?-b_:b_;
	while (a*b) (a>=b)? a=a%b : b=b%a;
	return a+b;
},

"getMultipliers" : function ( x ) {
	if (x instanceof PCM.multiplication_fn ) {
		return x.__enum();
	} else if (x instanceof PCM.minus_fn ) {
		var r = PCM.getMultipliers( x.arg1 );
		r[r.length] = -1;
		return r;
	} else if (x instanceof PCM.power_fn ) {
		var r = PCM.getMultipliers( x.arg1 );
		var res = [];
		for( var i=0;i<r.length;++i ) {
			res[res.length] = PCM.power( r[i], x.arg2 );
		}
		return res;
	}
	return [ x ];
}
, "calculate" : function ( arg, ctx ) {
	if ( PCM.isNumber( arg ) ) {
		return arg;
	}
	return arg.calculate( ctx );
}
, "division_fn" : function ( num, den ) {
	this.arg1 = num;
	this.arg2 = den;
	this.__enum = __enum_Scalar;
	this.getValue = function () {
		return  "("+PCM.getValue( this.arg1 ) + ")/(" + PCM.getValue( this.arg2 ) +")";
	}
	this.getTeX = function () {
		return  '\\frac{'+PCM.getTeX( this.arg1 ) + "}{" + PCM.getTeX( this.arg2 ) +"}";
	}
	this.getMath = function () {
		return  GetMultiplierMath( this.arg1 ) + "/" + GetMultiplierMath( this.arg2 );
	}
	this.getDerivative = function() {
		return PCM.division( 
			PCM.sum(  [
				PCM.multiplication( [ PCM.derivative( this.arg1 ), this.arg2 ] ),
				PCM.minus( PCM.multiplication( [ this.arg1 , PCM.derivative( this.arg2 ) ] ) )
			]),
			PCM.power( this.arg2, 2 )
		);
	};

	this.__clone = function( arr ) {
		var res = PCM.division( arr[0],arr[1] );
		return res;
	}

	this.calculate = function( ctx ) {
		return PCM.calculate( this.arg1,ctx )/PCM.calculate( this.arg2,ctx );
	}
}

, "division" : function ( num, den ) {
	if ( num instanceof PCM.division_fn && den instanceof PCM.division_fn ) {
		return PCM.division( PCM.multiplication( [num.arg1, den.arg2] ), PCM.multiplication( [num.arg2, den.arg1] ) );
	} else if ( num instanceof PCM.division_fn ) {
		var res = PCM.division( num.arg1,PCM.multiplication([num.arg2,den]) );
		return res;
	} else if ( den instanceof PCM.division_fn ) {
		return PCM.division( PCM.multiplication([num,den.arg2]), den.arg1);
	}
	var numArr = 	PCM.getMultipliers( num );
	var denArr = PCM.getMultipliers( den );
	for(var i=0;i<numArr.length;++i ) {
		for(var j=0;j<denArr.length;++j ) {
			var n = numArr[i];
			var d = denArr[j];
			if ( PCM.getValue( n ) ==  PCM.getValue( d ) ) {
				denArr[j] = 1;
				numArr[i] = 1;
			} else if ( PCM.isNumber( n ) && PCM.isNumber( d ) && n==Math.round(n) && d==Math.round(d)) {
				n = PCM.getNumber( n );
				d = PCM.getNumber( d );
				var nod = PCM.getNod(n,d);
				denArr[j] = d/nod;
				numArr[i] = n/nod;
			} else {
				continue;
			}
			break;
		}		
	}		
	var n = PCM.multiplication( numArr );
	var d = PCM.multiplication( denArr );

	var n0 = PCM.isNumber( n );
	var n1 = PCM.isNumber( d );
	var res;
	if ( n0 && PCM.getNumber( n ) == 0 ) {
		res = 0;
	} else if ( n1 && PCM.getNumber( d ) == 1 ) {
		res = n;
	} else {
		res = new PCM.division_fn( n, d );
	}
	return res;
},


"multiplication" : function ( arr ) {
	var result= [];
	var sign = false;
	for( var i=0;i<arr.length;++i ) {
		var multipliers = PCM.getMultipliers( arr[i] );
		for( var k=0;k<multipliers.length;++k ) {
			var current = multipliers[k];
			if ( current == -1 ) {
				sign=!sign;
				continue;
			}
			var multiplied = false;
			for( var j=0;j<result.length;++j ) {
				var res= tryMultiply( result[j], current );
				if ( typeof(res)!='undefined'  ) {
					result[j] = res;
					multiplied = true; 
					break;
				}
		
			}
			if (!multiplied) {
				result[result.length] = current;
			}
		}
	}	
	var res = (result.length == 1)? result[0] : (result.length == 0)?1:new PCM.multiplication_fn(result);
	if (sign) {
		return PCM.minus(res);
	}
	return res;
},

"multiplication_fn" : function ( args ) {
	this.args = args;
	this.__enum = __enum_Array;
	this.sorted = false;
	this.sort = function () {
		this.args.sort( complexityDescSort );
	}
	this.getValue = function () {
		this.sort();
		var res = "";
		for( var i=0;i<this.args.length;++i ) {
			res = res + '*' + PCM.getValue(this.args[i]);
		}
		return res.substring(1);
	}
	this.getTeX = function () {
		this.sort();
		var res = "";
		var cdot='';
		for( var i=0;i<this.args.length;++i ) {
			res = res + cdot + ' ' + GetMultiplierTeX( this.args[i] );
			cdot="\\cdot";
		}
		return res;
	}
	this.getMath = function () {
		this.sort();
		var res = "";
		var cdot='';
		for( var i=0;i<this.args.length;++i ) {
			res = res + cdot + GetMultiplierMath( this.args[i] );
			cdot="*";
		}
		return res;
	}

	this.__clone = function( arr ) {
		return PCM.multiplication( arr );
	}

	this.getDerivative = function () {	
		var sumArgs = [];
		for( var i=0;i<this.args.length;++i ) {
			var mulArgs = [];
			for( var j=0;j<this.args.length;++j ) {
				mulArgs[mulArgs.length] = i==j?PCM.derivative(this.args[j]):this.args[j];
			}
			sumArgs[ sumArgs.length ] = PCM.multiplication( mulArgs );
		}
		return PCM.sum( sumArgs );
	}
	this.calculate = function( ctx ) {
		var res = 1;
		for( var i=0;i<this.args.length;++i ) {
			res*=PCM.calculate( this.args[i],ctx );
		}
		return res;
	}
}

, "sum" : function ( args ) {
	var num = 0;
	var solved = [];
	for( var i=0;i<args.length;++i ) {
		var arg = args[i];
		if ( PCM.isNumber( arg ) ) {
			num+=PCM.getNumber( args[i] );
		} else {
			solved[solved.length] = args[i];
		}
	}
	if ( !solved.length ) {
		return num;
	}
	if ( num ) {
		solved[solved.length] = num;
	}
	return solved.length==1?solved[0]:new PCM.sum_fn( solved );

}

, "sum_fn" : function( args ) {
	this.args = args;
	this.__enum = __enum_Array;
	this.getValue = function () {
		var res = "";
		for( var i=0;i<this.args.length;++i ) {
			var val = new String( PCM.getValue(this.args[i]) );
			if ( (val.length>0 && val.charAt(0)=='-') || res.length == 0) {
				res = res + val;
			} else {
				res = res + '+' + val;
			}
		}
		return "(" + res + ")";
	}
	this.getTeX = function () {
		var res = "";
		for( var i=0;i<this.args.length;++i ) {
			var val = new String( PCM.getValue(this.args[i]) );
			if ( (val.length>0 && val.charAt(0)=='-') || res.length == 0) {
				res = res + PCM.getTeX(this.args[i]);
			} else {
				res = res + '+' + PCM.getTeX(this.args[i]);
			}
		}
		return res;
	}
	this.getMath = function () {
		var res = "";
		for( var i=0;i<this.args.length;++i ) {
			var val = new String( PCM.getValue(this.args[i]) );
			if ( (val.length>0 && val.charAt(0)=='-') || res.length == 0) {
				res = res + PCM.getMath(this.args[i]);
			} else {
				res = res + '+' + PCM.getMath(this.args[i]);
			}
		}
		return res;
	}

	this.getDerivative = function() {
		var solved = [];
		for( var i=0;i<this.args.length;++i ) {
			if ( !PCM.isConstant( this.args[i] ) ) {
				solved[solved.length] = PCM.derivative( this.args[i] );
			}
		}
		return PCM.sum( solved );
	}
	this.__clone = function( arr ) {
		return PCM.sum( arr );
	}
	this.calculate = function( ctx ) {
		var res = 0;
		for( var i=0;i<this.args.length;++i ) {
			res+=PCM.calculate( this.args[i],ctx );
		}
		return res;
	}
}

, "substraction" : function( x, y ) {
	return PCM.sum( [ x, PCM.minus( y ) ] );
}

, "power" : function( base, pw ) {
	if ( PCM.isNumber( base ) && PCM.isNumber( pw ) ) {
		var b = PCM.getNumber(base);
		var p = PCM.getNumber(pw);
		if ( p<0 ) {
			return PCM.division(1,PCM.power(base,-p) );
		}
		return Math.pow( b,p );
	}
	if ( PCM.isNumber( pw ) ) {
		var val = PCM.getNumber(pw);
		if ( val == 0 ) {	
			return 1;
		}
		if ( val == 1 ) {	
			return base;
		}
	} else if ( PCM.isNumber( base ) ) {
		var bv = PCM.getNumber(base);
		if ( bv==0 ) {
			return 0;
		}
		if ( bv==1 ) {
			return 1;
		}
	}
	if ( base instanceof PCM.power_fn ) {
		return new PCM.power_fn( base.arg1, PCM.multiplication([pw,base.arg2]) );
	}
	return new PCM.power_fn( base, pw );

}

, "power_fn" : function( base, pw ) {
	this.arg1 = base;
	this.arg2 = pw;
	this.__enum = __enum_Scalar;

	this.getValue = function () {
		return '('+PCM.getValue(this.arg1) + ')^' + PCM.getValue(this.arg2) ;
	}
	this.getTeX= function () {
		if ( typeof(this.arg1)=='object' && this.arg1.immediatepowersign ) {
			return '{\\'+ this.arg1.name + '}^{' + PCM.getTeX(this.arg2) +'}\\left({' + PCM.getTeX(this.arg1.arg1) +'}\\right)';
		}
		return '{'+  GetPowerBaseTeX(this.arg1) + '}^{' + PCM.getTeX(this.arg2) +'}';
	}
	this.getMath= function () {
		return GetPowerBaseMath(this.arg1) + '^' + GetPowerBaseMath(this.arg2);
	}

	this.__clone = function( arr ) {
		return PCM.power( arr[0], arr[1] );
	}

	this.getDerivative = function () {	
		var baseConst = PCM.isConstant( this.arg1 );
		var powerConst = PCM.isConstant( this.arg2 );
		if ( baseConst && powerConst ) {
			return 0;
		} else if ( baseConst ) {  //exponential function
			var arr=[ this, PCM.ln( this.arg1 ) ];
			if ( PCM.getValue(this.arg2) != "x" ) { //power is a function
				arr[arr.length] = PCM.derivative( this.arg2 );
			}
			return PCM.multiplication(arr);
		} else if ( powerConst ) { //power function (f(x)^a)' = a*f'(x)*f(x)^(a-1)
			var arr=[ this.arg2, PCM.power( this.arg1, PCM.sum([ this.arg2, -1 ]) ) ];
			if ( PCM.getValue(this.arg1) != "x" ) { //base is a function
				arr[arr.length] = PCM.derivative( this.arg1 );
			}
			return PCM.multiplication(arr);
		} else { // power-exponential function 	(f(x)^g(x))' = exp(ln(f(x))*g(x))
			return PCM.derivative( new PCM.power( PCM.exp(), PCM.multiplication([ PCM.ln(this.arg1),  this.arg2 ] )) );
		}
	}
	this.calculate = function( ctx ) {
		return Math.pow(PCM.calculate( this.arg1,ctx ),PCM.calculate( this.arg2,ctx ));
	}

}


, "minus" : function ( x ) {
	if ( PCM.isNumber(x) ) {
		return -PCM.getNumber( x );
	} else if ( x instanceof PCM.minus_fn ) {
		return x.arg1;
	} else if ( x instanceof PCM.division_fn ) {
		return PCM.division( PCM.minus( x.arg1 ), x.arg2 );
	} else if ( x instanceof PCM.multiplication_fn ) {
		if ( x.args[0] instanceof PCM.minus_fn ) {
			x.args[0] = x.args[0].arg1;
			return x;
		} else if ( PCM.isNumber(x.args[0]) ) {
			x.args[0] = -PCM.getNumber(x.args[0]);
			return x;
		}
	}
	return new PCM.minus_fn( x );
}

, "minus_fn" : function ( x ) {
	initOneArgFunction( this, x, "minus", PCM.minus );
	this.immediatepowersign = false;
	this.getValue = function () {
		return '-' + PCM.getValue(this.arg1);
	}
	this.getTeX= function () {
		return '-'+ GetMultiplierTeX( this.arg1 );
	}
	this.getMath= function () {
		return '-'+GetMultiplierMath( this.arg1 );
	}
	this.getDerivative = function () {	
		return PCM.minus(PCM.derivative( x ) );
	}
	this.calculate = function( ctx ) {
		return -PCM.calculate( this.arg1,ctx );
	}
}


, "sin" : function ( x ) {
	return new PCM.sin_fn( x );
}

, "sin_fn" : function ( x ) {
	initOneArgFunction( this, x, "sin", PCM.sin );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.cos( this.arg1 ));
	}
	this.calculate = function( ctx ) {
		return Math.sin( PCM.calculate( this.arg1,ctx ) );
	}
}


, "cos" : function ( x ) {
	return new PCM.cos_fn( x );
}

, "cos_fn" : function( x ) {
	initOneArgFunction( this, x, "cos", PCM.cos );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.minus(PCM.sin( this.arg1 )));
	}
	this.calculate = function( ctx ) {
		return Math.cos( PCM.calculate( this.arg1,ctx ) );
	}
}

, "ln" : function( x ) {
	if ( x instanceof PCM.exp_fn ) {
		return 1;
	}
	return new PCM.ln_fn( x );
}

, "ln_fn" : function( x ) {
	initOneArgFunction( this, x, "ln", PCM.ln );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.division( 1 , this.arg1 ) );
	}
	this.calculate = function( ctx ) {
		return Math.log( PCM.calculate( this.arg1,ctx ) );
	}

}

, "lg" : function ( x ) {
	return new PCM.lg_fn( x );
}

, "lg_fn" : function ( x ) {
	initOneArgFunction( this, x, "lg", PCM.lg );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.division( 1,  PCM.multiplication( [ this.arg1,  PCM.ln( 10 ) ]  ) ) );
	}
	this.calculate = function( ctx ) {
		return Math.log( PCM.calculate( this.arg1,ctx ) )/Math.log(10);
	}

}

, "lb" : function( x ) {
	return new PCM.lb_fn( x );
}

, "lb_fn" : function( x ) {
	initOneArgFunction( this, x, "lb", PCM.lb );
	initUnknownFunctionTeX( this );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.division( 1,  PCM.multiplication( [ this.arg1,  PCM.ln( 2 ) ]  ) ) );
	}
	this.calculate = function( ctx ) {
		return Math.log( PCM.calculate( this.arg1,ctx ) )/Math.log(2);
	}
}


, "logn" : function ( x,y ) {
	return new PCM.logn_fn( x,y );
}

, "logn_fn" : function ( x,y ) {
	initOneArgFunction( this, x, "log_" + y, PCM.logn );
	this.getMath= function () {
		return "log" + this.arg2 + "(" + PCM.getMath( this.arg1 ) + ")";
	}

	this.arg2 = y;
	this.__clone = function( arr ) {
		return PCM.logn( arr[0],arr[1] );
	}	
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.division( 1,  PCM.multiplication( [ this.arg1,  PCM.ln( this.arg2 ) ]  ) ) );
	}
	this.calculate = function( ctx ) {
		return Math.log( PCM.calculate( this.arg1,ctx ) )/Math.log(this.arg2);
	}

}

, "cosh_fn" : function ( x ) {
	initOneArgFunction( this, x, "cosh", PCM.cosh );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.sinh( this.arg1 ));
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return (Math.exp( x )+Math.exp( -x ))/2;
	}
}

, "cosh" : function ( x ) {
	return new PCM.cosh_fn( x );
}

, "sinh_fn" : function( x ) {
	initOneArgFunction( this, x, "sinh", PCM.sinh );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.cosh( this.arg1 ));
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return (Math.exp( x )-Math.exp( -x ))/2;
	}
}

, "sinh" : function( x ) {
	return new PCM.sinh_fn( x );
}

, "sech_fn" : function( x ) {
	initOneArgFunction( this, x, "sech", PCM.sech );
	initUnknownFunctionTeX( this );
	this.getDerivative = function () {	
		return PCM.division( 1,  PCM.cosh( this.arg1 ) ).getDerivative();
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return 2/(Math.exp( x )+Math.exp( -x ));
	}

}

, "sech" : function( x ) {
	return new PCM.sech_fn( x );
}


, "csch_fn" : function( x ) {
	initOneArgFunction( this, x, "csch", PCM.csch );
	initUnknownFunctionTeX( this );
	this.getDerivative = function () {	
		return PCM.division( 1,  PCM.sinh( this.arg1 ) ).getDerivative();
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return 2/(Math.exp( x )-Math.exp( -x ));
	}
}

, "csch" : function( x ) {
	return new PCM.csch_fn( x );
}

, "tanh_fn" : function( x ) {
	initOneArgFunction( this, x, "tanh", PCM.tanh );
	this.getDerivative = function () {	
		return SolveComplexDerivative( this.arg1, PCM.division( 1,  PCM.power(  PCM.cosh(this.arg1),2) ) );
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return (Math.exp( 2*x )-1)/(Math.exp( 2*x )+1);
	}

}

, "tanh" : function ( x ) {
	return new PCM.tanh_fn( x );
}

, "coth_fn" : function( x ) {
	initOneArgFunction( this, x, "coth", PCM.coth );
	this.getDerivative = function () {	
		return SolveComplexDerivative( this.arg1, PCM.division( -1,  PCM.power(  PCM.sinh(this.arg1),2) ) );
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return (Math.exp( 2*x )+1)/(Math.exp( 2*x )-1);
	}

}

, "coth" : function( x ) {
	return new PCM.coth_fn( x );
}

, "variable_fn" : function( x ) {
	this.getValue = function () {
		return 'x';
	}
	this.getTeX = function () {
		return '{x}';
	}
	this.getMath = function () {
		return 'x';
	}
	this.__enum = function() {
		return [ ];
	}

	this.__clone = function( arr ) {
		return new PCM.variable_fn( );
	}
	this.getDerivative = function () {	
		return 1;
	}
	this.calculate = function( ctx ) {
		return ctx['x'];
	}

}

, "sqrt_fn" : function( x ) {
	initOneArgFunction( this, x, "sqrt", PCM.sqrt );
	this.immediatepowersign = false;
	this.getTeX = function () {
		return '\\sqrt{' + PCM.getTeX( this.arg1 ) + '}';
	}

	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.division(  1, PCM.multiplication( [ 2, PCM.sqrt(this.arg1)]) ));
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return Math.sqrt( x );
	}

}
, "sqrt" : function ( x ) {
	return new PCM.sqrt_fn( x );
}

, "root_fn" : function( x, y ) {
	this.arg1 = x;
	this.arg2 = y;
	this.immediatepowersign = false;
	this.name = "root";
	this.__enum = function() { return [ this.arg1, this.arg2 ]; }

	this.getValue = function () {
		return this.name + this.arg2 + '(' + PCM.getValue(this.arg1) + ')';
	}
	this.__clone = function( arr ) {
		return PCM.root( arr[0],arr[1] );
	}
	this.getTeX = function () {
		return '{\\small^' + PCM.getTeX( this.arg2 ) + '}\\sqrt{' + PCM.getTeX( this.arg1 ) + '}';
	}
	this.getMath = function () {
		return 'root' + this.arg2 + '(' + PCM.getMath( this.arg1 ) + ')';
	}
	this.getDerivative = function () {	
		var powfn = new PCM.power_fn( this.arg1, PCM.division(1,this.arg2));
		return powfn.getDerivative();
	}
	this.calculate = function( ctx ) {
		var x1 = PCM.calculate( this.arg1,ctx );
		return Math.pow( x1, 1/this.arg2 );
	}

}
, "root" : function ( x,y ) {
	return new PCM.root_fn( x,y );
}

, "exp_fn" : function ( x ) {
	this.getValue = function () {
		return 'e';
	}
	this.getTeX = function () {
		return 'e';
	}
	this.getMath = function () {
		return 'e';
	}
	this.__enum = function() {
		return [ ];
	}

	this.__clone = function( arr ) {
		return new PCM.exp_fn( );
	}
	this.getDerivative = function () {	
		return 0;
	}
	this.calculate = function( ctx ) {
		return Math.exp(1);
	}
}
, "exp" : function( ) {
	return new PCM.exp_fn( );
}

, "tan_fn" : function( x ) {
	initOneArgFunction( this, x, "tan", PCM.tan );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.division( 1, PCM.power( PCM.cos( this.arg1 ), 2 )  ) );
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return Math.tan( x );
	}

}

, "tan" : function( x ) {
	return new PCM.tan_fn( x );
}

, "cot_fn" : function( x ) {
	initOneArgFunction( this, x, "cot", PCM.cot );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.division( -1, PCM.power( PCM.sin( this.arg1 ), 2 )  ) );
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return 1/Math.tan( x );
	}
}
, "cot" : function( x ) {
	return new PCM.cot_fn( x );
}


, "sec_fn" : function( x ) {
	initOneArgFunction( this, x, "sec", PCM.sec );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.division( PCM.sin( this.arg1 ), PCM.power( PCM.cos( this.arg1 ), 2 )  ) );
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return 1/Math.cos( x );
	}
}
, "sec" : function( x ) {
	return new PCM.sec_fn( x );
}


, "csc_fn" : function( x ) {
	initOneArgFunction( this, x, "csc", PCM.csc );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.division( PCM.cos( this.arg1 ), PCM.power( PCM.sin( this.arg1 ), 2 )  ) );
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return 1/Math.sin( x );
	}
}
, "csc" : function( x ) {
	return new PCM.csc_fn( x );
}


, "arctan_fn" : function( x ) {
	initOneArgFunction( this, x, "arctan", PCM.arctan );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1, PCM.division( 1,  PCM.sum( [ 1,  PCM.power(  this.arg1 , 2 ) ] ) ) );
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return Math.atan( x );
	}
}
, "arctan" : function( x ) {
	return new PCM.arctan_fn( x );
}

, "arccot_fn" : function( x ) {
	initOneArgFunction( this, x, "arccot", PCM.arccot );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1, PCM.division( -1,  PCM.sum( [ 1,  PCM.power(  this.arg1 , 2 ) ] ) ) );
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return Math.PI/2-Math.atan( x );
	}
}
, "arccot" : function( x ) {
	return new PCM.arccot_fn( x );
}

, "arcsin_fn" : function( x ) {
	initOneArgFunction( this, x, "arcsin", PCM.arcsin );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1, PCM.division( 1,
				 PCM.sqrt( PCM.substraction( 1,  PCM.power( this.arg1 , 2 ) ) )
				) );
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return Math.asin( x );
	}
}
, "arcsin" : function( x ) {
	return new PCM.arcsin_fn( x );
}

, "arccos_fn" : function( x ) {
	initOneArgFunction( this, x, "arccos", PCM.arccos );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1, PCM.division( -1,
				 PCM.sqrt( PCM.substraction( 1,  PCM.power( this.arg1, 2 ) ) )
				) );
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return Math.acos( x );
	}
}
, "arccos" : function( x ) {
	return new PCM.arccos_fn( x );
}
, "arcsec_fn" : function( x ) {
	initOneArgFunction( this, x, "arcsec", PCM.arcsec );
	initUnknownFunctionTeX( this );

	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1, PCM.division( 1, 
				 PCM.multiplication([
					 PCM.power( this.arg1, 2 ),
					 PCM.sqrt( 
						 PCM.sum( [ 1, 
							 PCM.minus(  PCM.power( this.arg1, 2 ) )
						] ) 
					)
				])
			));
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return Math.acos( 1/x );
	}
}

, "arcsec" : function ( x ) {
	return new PCM.arcsec_fn( x );
}


, "arccosec_fn" : function( x ) {
	initOneArgFunction( this, x, "arccosec", PCM.arccosec );
	initUnknownFunctionTeX( this );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1, PCM.division( -1, 
				 PCM.multiplication([
					 PCM.power( this.arg1, 2 ),
					 PCM.sqrt( PCM.substraction( 1,  PCM.power( this.arg1, 2 ) ) )
				])
				));
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return Math.PI/2-Math.acos( 1/x );
	}
}

, "arccosec" : function ( x ) {
	return new PCM.arccosec_fn( x );
}




, "function_fn" : function ( x,name ) {	
	initOneArgFunction( this, x, name , null );
	initUnknownFunctionTeX( this );
	this.__clone = function( arr ) {
		return new PCM.function_fn( arr[0], this.name );
	}
	var inlineDerivativeFuncs = {
		"versin" : function ( x ) {
			return  PCM.sin( x );
		},
		"vercos" : function ( x ) {
			return  PCM.minus(   PCM.cos( x )  );
		},
		"haversin" : function ( x ) {
			return  PCM.division(   PCM.sin( x ) , 2 );  
		},
		"exsec" : function ( x ) {
			return  PCM.division(  PCM.sin(x) ,  PCM.power(  PCM.cos( x ), 2 )  );
		},
		"excsc" : function ( x ) {
			return  PCM.division(  PCM.minus(  PCM.cos(x) ),  PCM.power(  PCM.sin( x ), 2 )  );
		}
	}

	var inlineCalcFuncs = {
		"versin" : function ( x ) {
			return  1-Math.cos( x );
		},
		"vercos" : function ( x ) {
			return  1+Math.cos( x );
		},
		"haversin" : function ( x ) {
			return  (1-Math.cos( x ))/2;
		},
		"exsec" : function ( x ) {
			return  1/Math.cos( x )-1;
		},
		"excsc" : function ( x ) {
			return  1/Math.sin( x )-1;
		}
	}

	this.getDerivative = function ( ) {
		if ( PCM.isConstant( this.arg1 ) ) {
			return 0;
		}
		var func = inlineDerivativeFuncs[this.name];
		if ( func ) {
			return SolveComplexDerivative( this.arg1, func( this.arg1 ) )
		}
		return ;
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		var f = inlineCalcFuncs[this.name];
		return f( x );
	}
}
, "abs" : function ( x ) {
	return new PCM.abs_fn( x );
}
, "abs_fn" : function( x ) {
	initOneArgFunction( this, x, "abs", PCM.abs );
	this.getDerivative = function () {	
		return SolveComplexDerivative(this.arg1,PCM.sign( -1, this.arg1 ) );
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		return Math.abs( x );
	}
	this.getTeX= function () {
		return '\\left|'+ PCM.getTeX(this.arg1) + '\\right|';
	}

}
, "sign" : function ( x ) {
	if ( PCM.isNumber( x ) ) {
		return x<0?-1:(x>0)?1:0;
	}
	return new PCM.sign_fn( x );
}
, "sign_fn" : function( x ) {
	initOneArgFunction( this, x, "sign", PCM.sign );
	initUnknownFunctionTeX( this );
	this.getDerivative = function () {	
		return 0;
	}
	this.calculate = function( ctx ) {
		var x = PCM.calculate( this.arg1,ctx );
		 
		return x<0?-1:(x>0)?1:0;
	}
}


, "pi_fn" : function( ) {
	this.__enum = function() {
		return [];
	}

	this.__clone = function( arr ) {
		return new PCM.pi_fn();
	}
	this.getValue = function() {
		return "pi";
	}
	this.getTeX = function() {
		return '\\pi';
	}
	this.getMath = function() {
		return 'pi';
	}
	this.getDerivative = function() {
		return 0;
	}
	this.calculate = function( ctx ) {
		return Math.PI;
	}
}

, "derivative_fn" : function( x ) {
	this.arg1 = x;
	this.__enum = __enum_Scalar;

	this.__clone = function( arr ) {
		return PCM.derivative( arr[0] );
	}
	this.getValue = function() {
		return "f'(" + PCM.getValue(this.arg1) + ")";
	}
	this.getTeX = function() {
		return '{f^\\prime}\\left(' + PCM.getTeX(this.arg1) + '\\right)';
	}
	this.getMath = function() {
		return 'derivative(' + PCM.getMath(this.arg1) + ')';
	}
	this.getDerivative = function() {
		return this.arg1.getDerivative();
	}
}

, "derivative" : function( x ) {
	if ( PCM.isConstant( x ) ) {
		return 0;
	}
	return new PCM.derivative_fn( x );
}


, "translate" : function( syntaxTree ) {
	var translator = new ParsingPrimitivesTranslator();
	return translator.__translate( syntaxTree );
}

, "grammar" : function () {
this["digit"]={ "t":"|", "v":["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]};
this["plus sign"]="+";
this["power sign"]="^";
this["minus sign"]="-";
this["dot"]=".";
this["left paren"]="(";
this["right paren"]=")";
this["asterisk"]="*";
this["solidus"]="/";
this["dotorcomma"]={ "t":"|", "v":[".", ","]};
this["unsigned integer"]={ "t":"&", "v":[{ "t":"->", "v":"digit"}, { "t":"*", "v":{ "t":"->", "v":"digit"}}]};
this["exact numeric literal"]={ "t":"|", "v":[{ "t":"&", "v":[{ "t":"->", "v":"unsigned integer"}, { "t":"|", "v":[{ "t":"&", "v":[{ "t":"->", "v":"dotorcomma"}, { "t":"|", "v":[{ "t":"->", "v":"unsigned integer"},""]}]},""]}]}, { "t":"&", "v":[{ "t":"->", "v":"dotorcomma"}, { "t":"->", "v":"unsigned integer"}]}]};
this["mantissa"]={ "t":"->", "v":"exact numeric literal"};
this["signed integer"]={ "t":"&", "v":[{ "t":"|", "v":[{ "t":"->", "v":"sign"},""]}, { "t":"->", "v":"unsigned integer"}]};
this["sign"]={ "t":"|", "v":[{ "t":"->", "v":"plus sign"}, { "t":"->", "v":"minus sign"}]};
this["exponent"]={ "t":"->", "v":"signed integer"};
this["approximate numeric literal"]={ "t":"&", "v":[{ "t":"->", "v":"mantissa"}, "E", { "t":"->", "v":"exponent"}]};
this["unsigned numeric literal"]={ "t":"|", "v":[{ "t":"->", "v":"approximate numeric literal"}, { "t":"->", "v":"exact numeric literal"}]};
this["variable"]="x";
this["pi"]="pi";
this["exponenta"]={ "t":"|", "v":["e", "E"]};
this["paren expression"]={ "t":"&", "v":[{ "t":"->", "v":"left paren"}, { "t":"->", "v":"expression"}, { "t":"->", "v":"right paren"}]};
this["value"]={ "t":"|", "v":[{ "t":"->", "v":"unsigned numeric literal"}, { "t":"->", "v":"variable"}, { "t":"->", "v":"func"}, { "t":"->", "v":"funcnum"}, { "t":"->", "v":"pi"}, { "t":"->", "v":"exponenta"}, { "t":"->", "v":"paren expression"}]};
this["factor"]={ "t":"&", "v":[{ "t":"|", "v":[{ "t":"->", "v":"sign"},""]}, { "t":"->", "v":"value"}]};
this["factoroperator"]={ "t":"|", "v":[{ "t":"->", "v":"asterisk"}, { "t":"->", "v":"solidus"}]};
this["power"]={ "t":"&", "v":[{ "t":"->", "v":"factor"}, { "t":"*", "v":{ "t":"&", "v":[{ "t":"->", "v":"power sign"}, { "t":"->", "v":"factor"}]}}]};
this["product"]={ "t":"&", "v":[{ "t":"->", "v":"power"}, { "t":"*", "v":{ "t":"&", "v":[{ "t":"->", "v":"factoroperator"}, { "t":"->", "v":"power"}]}}]};
this["sum"]={ "t":"&", "v":[{ "t":"->", "v":"product"}, { "t":"*", "v":{ "t":"&", "v":[{ "t":"->", "v":"sign"}, { "t":"->", "v":"product"}]}}]};
this["func"]={ "t":"&", "v":[{ "t":"->", "v":"func name"}, { "t":"->", "v":"left paren"}, { "t":"->", "v":"expression"}, { "t":"->", "v":"right paren"}]};
this["funcnum"]={ "t":"&", "v":[{ "t":"->", "v":"funcnum name"}, { "t":"->", "v":"unsigned integer"}, { "t":"->", "v":"left paren"}, { "t":"->", "v":"expression"}, { "t":"->", "v":"right paren"}]};
this["func name"]={ "t":"|", "v":["sin", "cosec", "cos", "tg", "tan", "ctg", "cot", "sech", "sec", "arcsin", "arccosec", "arccos", "arctg", "arctan", "arcctg", "arccot", "arcsec", "exp", "lb", "lg", "ln", "versin", "vercos", "haversin", "exsec", "excsc", "sqrt", "sh", "ch", "th", "cth", "csch", "tanh", "coth", "abs", "sgn", "sign"]};
this["funcnum name"]={ "t":"|", "v":["root", "log"]};
this["expression"]={ "t":"->", "v":"sum"};

this._getRootRule = function() {
	return { "t":"->", "v":"expression" };
}
}
};
}();
