<!-- HIDE FROM OTHER BROWSERS

// JavaScript for Chemistry: Contains objects for 
//    Substance and Reaction
//
// Copyright 1997, J. A. Bertrand - All rights reserved

// GLOBAL VARIABLES

var Pos = 0
var formula2 = ""
var EPos = 0
var equat2 = ""
var fMatrix = new Array()
var trouble = false

var gpnoArr = new Array(0,1,8,1,2,3,4,5,6,7,8,1,2,3,4,5,6,7,8,1,2,9,9,9,9,9,9, 
9,9,9,2,3,4,5,6,7,8,1,2,9,9,9,9,9,9,9,9,9,2,3,4,5,6,7,8,1,2,9,9,9,9,9,9,9,9, 
9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,2,3,4,5,6,7,8,1,2,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 
9)

function getAtnum(elem) {

var elemArr = new Array("","H","He","Li","Be","B","C","N","O","F","Ne","Na",
             "Mg","Al","Si","P","S","Cl","Ar","K","Ca","Sc","Ti","V","Cr",
             "Mn","Fe","Co","Ni","Cu","Zn","Ga", "Ge","As","Se","Br","Kr",
             "Rb","Sr","Y","Zr","Nb","Mo","Tc","Ru","Rh","Pd", "Ag","Cd",
             "In","Sn","Sb","Te","I","Xe","Cs","Ba","La","Ce","Pr","Nd",
             "Pm", "Sm","Eu","Gd","Tb","Dy","Ho","Er","Tm","Yb","Lu","Hf",
             "Ta","W","Re","Os", "Ir","Pt","Au","Hg","Tl","Pb","Bi","Po",
             "At","Rn","Fr","Ra","Ac","Th","Pa", "U","Np","Pu","Am","Cm",
             "Bk","Cf","Es","Fm","Md","No","Lr")

var Temp = 0

     for (var i = 1; i <= 102; i++) {
          if (elem == elemArr[i]) {
               Temp = i
               break
          }
     }
     return Temp
}

function getAtwt(elem) {

var atwtArr = new Array(0,1.008,4.003,6.941,9.012,10.81,12.01,14.01,16,19,20.18,22.99,24.31,
26.98,28.09,30.97,32.06,35.45,39.95,39.1,40.08,44.96,47.88,50.94,52,54.94,
55.85,58.93,58.69,63.55,65.38,69.72,72.59,74.92,78.96,79.90,83.8,85.47,87.62,88.91,91.22,92.91,95.94,98,101.1,102.9,106.4,107.9,112.4,114.8,118.7,121.8,
127.6,126.9,131.3,132.9,137.3,138.9,140.1,140.9,144.2,145,150.4,152,157.3,
158.9,162.5,164.9,167.3,168.9,173,175,178.5,180.9,183.9,186.2,190.2,192.2,
195.1,197,200.6,204.4,207.2,209,209,210,222,223,226,227,232,231,238,237,244,
243,247,247,251,252,257,258,259,260)

   var atNum = getAtnum(elem)
   var atWt = atwtArr[atNum]

   return atWt
}


function getMolwt() {

var atWt = 0
var Temp = 0

     for (var i = 1; i <= this.elem[0]; i++) {
          atWt = getAtwt(this.elem[i])
          Temp += atWt * this.numel[i]
     }
     this.molwt = Temp
}

function getShape()  {

row0 = new Array("","","","","","","","")
row1 = new Array("","Linear","Linear","Planar Triangle","Tetrahedron",
"Trigonal Bipyramid","Octahedron","Not Predictable")
row2 = new Array("","Not Possible","Linear","Bent 120 degrees",
"Trigonal Pyramid","SeeSaw","Square Pyramid","Not Predictable")
row3 = new Array("","Not Possible","Not Possible","Linear",
"Bent 109 degrees","T-Shaped","Square Planar","Not Predictable")
row4 = new Array("","Not Possible","Not Possible","Not Possible",
"Linear","Linear","T-Shaped","Not Predictable")

vseArr = new Array(5)
for (var i =0; i < 5; i++) {
     vseArr[i] = new Array(8)
}

for (i = 0; i < 8; i++) {
     vseArr[0][i] = row0[i]
     vseArr[1][i] = row1[i]
     vseArr[2][i] = row2[i]
     vseArr[3][i] = row3[i]
     vseArr[4][i] = row4[i]
}

var atNum = 0; var gpNo = 0; var atTyp = 0; var centElec = 0;
var nonBond = 0; var groups = 0; var Temp = 0

	for (var i = 1; i <= this.elem[0]; i++)  {
		atNum = getAtnum(this.elem[i])
		gpNo = gpnoArr[atNum]
		if (gpNo == 9) {
			alert
			break
		}

		if (this.elem[i] == "H") {
			atTyp = 0
		}
		else {
			atTyp = 6
		}

		if (i == 1) {
			centElec = gpNo - this.charge
		}
		else  {
			centElec = centElec + (gpNo - atTyp)*this.numel[i]
			nonBond = nonBond + this.numel[i]
		}
	}
	groups = Math.floor((centElec + 1)/2)
	nonBond = groups - nonBond
	this.shape = vseArr[nonBond + 1][groups]
}

function binName() { 

   // The naming of binary compounds follows the Oxtoby,Freeman,Block text
   //   and the vowel at the end of prefixes is not dropped before a vowel.

   var flag = true
   var temp = ""

   var typeElem = new Array("","N","I","M","M","N","N","N","N","N","I","M",
     "M", "M","N","N","N","N","I","M","M","T","T","T","T","T","T","T","T",
     "T","M","P","N","N","N","N","I","M","M","T","T","T","T","T","T","T",
     "T","T","M","P","P","P","N","N","I","M","M","T","R","R","R","R","R",
     "R","R","R","R","R","R","R","R","R","T","T","T","T","T","T","T","T",
     "M","P","P","P","P","N","I","M","M","A","A","A","A","A","A","A","A",
     "A","A","A","A","A","A","T","T","T","T","T","T","T")

   var elemName = new Array("","hydrogen","helium","lithium","beryllium","boron",
     "carbon","nitrogen","oxygen","fluorine","neon","sodium","magnesium",
     "aluminum","silicon","phosphorus","sulfur","chlorine","argon",
     "potassium","calcium","scandium","titanium","vanadium","chromium",
     "manganese","iron","cobalt","nickel","copper","zinc","gallium","germanium",
     "arsenic","selenium","bromine","krypton","rubidium","strontium",
     "yttrium","zirconium","niobium","molybdenum","technetium","ruthenium",
     "rhodium","palladium","silver","cadmium","indium","tin","antimony",
     "tellurium","iodine","xenon","cesium","barium","lanthanum","cerium",
     "praseodinium","neodymium","promethium","samarium","europium",
     "gadolinium","terbium","dysprosium","holmium","erbium","thulium",
     "ytterbium","lutetium","hafnium","tantalum","tungsten","rhenium",
     "osmium","iridium","platinum","gold","mercury","thallium","lead",
     "bismuth","polonium","astatine","radon","francium","radium","actinium",
     "thorium","protactinium","uranium","neptunium","plutonium","americium",
     "curium","berkelium","californium","einsteinium","fermium",
     "mendelevium","nobelium","lawrencium","rutherfordium","dubnium",
     "seaborgium","bohrium","hassium","meitnerium")

   var elemIde = new Array("","hydride","","","","boride","carbide","nitride",
     "oxide","fluoride","","","","","silicide","phosphide","sulfide",
     "chloride","","","","","","","","","","","","","","","germanide",
     "arsenide","selenide","bromide","","","","","","","","","","","","",
     "","","","antimonide","telluride","iodide")

   var enegativ = new Array(0,2.25,3.49,0.97,1.54,2.04,2.99,3.68,3.94,4.30,4.49,
     0.91,1.37,1.83,2.28,2.41,2.86,3.10,3.49,0.73,1.08,1.36,1.54,1.63,1.66,
     1.55,1.83,1.88,1.91,1.90,1.65,2.01,2.33,2.38,2.79,2.95,3.31,0.82,1.00,1.22,1.33,
     0.77,2.35,1.9,2.2,2.28,2.20,1.47,1.53,1.76,1.85,2.22,2.57,2.95,3.01,0.62,
     0.88,1.10,1.12,1.13,1.14,1.07,1.17,1.01,1.20,1.10,1.22,1.23,1.24,1.25,
     1.06,1.27,1.3,1.5,2.36,1.9,2.2,2.20,2.28,1.87,1.81,1.62,1.16,2.15,2.48,
     2.85,2.12,0.68,0.92,1.1,1.3,1.5,1.38,1.36,1.28,1.3,1.3,1.3,1.3,1.3,1.3,
     1.3,1.3)

   var prefix = new Array("","mono","di","tri","tetra","penta","hexa","hepta",
     "octa","nona")

   var romNum = new Array("","(I)","(II)","(III)","(IV)","(V)","(VI)","(VII)",
     "(VIII)","(IX)","(X)")

   // Check to see if binary
   if (this.elem[0] != 2) {
      alert("Error - this method is for binary compounds only!")
   } else {
      // Get Atomic Number
      var num1 = getAtnum(this.elem[1])
      var num2 = getAtnum(this.elem[2])
      // Get Electronegativities
      var eneg1 = enegativ[num1]
      var eneg2 = enegativ[num2]
      // Get Element Type
      var type1 = typeElem[num1]
      var type2 = typeElem[num2]
      // Set Flag for Least Electronegative
      if (eneg1 > eneg2) {
         flag = false
      }
      // Make First Element Most ElectroPositive, base name on Type
      if (flag) {
         if (type1 == "M") {
            temp = elemName[num1] + " " + elemIde[num2]
         } else if (type1 == "N") {
            if (this.numel[1] != 1) {
               temp += prefix[this.numel[1]]
            }
            temp += elemName[num1] + " "
            if (this.numel[2] != 1) {
               temp += prefix[this.numel[2]]
            } else if ((num1==6)||(num1==7)) {
               temp += prefix[1]
            }
            temp += elemIde[num2]
         } else if ((type1 == "T")||(type1 == "P")) {
            var numeral = (8 - gpnoArr[num2]) * this.numel[2]/this.numel[1]
            temp = elemName[num1] + romNum[numeral] + " " + elemIde[num2]
         }
      } else {
         if (type1 == "M") {
            temp = elemName[num2] + " " + elemIde[num1]
         } else if (type2 == "N") {
            if (this.numel[2] != 1) {
               temp += prefix[this.numel[2]]
            }
            temp += elemName[num2] + " "
            if (this.numel[1] != 1) {
               temp += prefix[this.numel[1]]
            } else if ((num2==6)||(num2==7)) {
               temp += prefix[1]
            }
            temp += elemIde[num1]
         } else if ((type2 == "T")||(type2 == "P")) {
            var numeral = (8 - gpnoArr[num1]) * this.numel[1]/this.numel[2]
            temp = elemName[num2] + romNum[numeral] + " " + elemIde[num1]
         }
      }
      this.name = temp
   }
}

function wrFormula() {

     var Temp = this.formula

     return Temp
}

function fmatForm() {

   var Temp = ""
   var Temp1 = ""
   var asType = 0

   formula2 = this.formula
   Pos = 0
   while (Pos <= (formula2.length - 1)) {

      asType = typeChar(formula2.charAt(Pos))
      if (asType == 3) {
         Temp = formula2.charAt(Pos)
         Temp1 += "<sub>" + evalNum(Temp) + "</sub>"
      }
      else if ((asType == 4)|| (asType == 7)) {
         Temp1 += "<sup>" + formula2.charAt(Pos)
         Pos += 1
         Temp = formula2.charAt(Pos)
         Temp1 += evalNum(Temp) + "</sup>"
      }
      else {
         Temp1 += formula2.charAt(Pos)
      }
      Pos += 1
   }
   return Temp1
}

function typeChar(chAtPos){

var isType = 0

if ((chAtPos >= "0") && (chAtPos <= "9")) {isType = 3}
    else if (chAtPos == "+") {isType = 4}
    else if (chAtPos == "(") {isType = 5}
    else if (chAtPos == ")") {isType = 6}
    else if (chAtPos == "-") {isType = 7}
    else if (chAtPos == ">") {isType = 8}
    else if (chAtPos == "=") {isType = 9}
    else if (chAtPos == " ") {isType = 10}
    else if (chAtPos == chAtPos.toUpperCase()) {isType = 1}
    else if (chAtPos == chAtPos.toLowerCase()) {isType = 2}
    else 
      {alert("Error in Entry - Character " & chAtPos)}

return isType
}

function evalNum(Temp) {

     // Uses Global variables formula2, Pos

     var Temp2 = Temp
     var Temp3 = 0

     if ((formula2.length > Pos) && 
         (formula2.charAt(Pos + 1) >= "0") &&
         (formula2.charAt(Pos + 1) <= "9"))  {
            Temp2 += formula2.charAt(Pos + 1)
            Pos += 1
            evalNum(Temp2)
     }
     Temp3 = parseInt(Temp2)
     return Temp3
}

function evalEnum(Temp) {

     //Uses Global variables equat2, EPos

     var Temp2 = Temp
     var Temp3 = 0

     if ((equat2.length > EPos) && 
         (equat2.charAt(EPos + 1) >= "0") &&
         (equat2.charAt(EPos + 1) <= "9"))  {
            Temp2 += equat2.charAt(EPos + 1)
            EPos += 1
            evalEnum(Temp2)
     }
     Temp3 = parseInt(Temp2)
     return Temp3
}


function parsForm(){

     // Uses Global variables formula2, Pos

     var El = 0
     var StartEl = 0
     var EndEl = 0
     var IQ = 0
     var Temp = " "
     var asType = 0

     this.charge = 0
     formula2 = this.formula
     Pos = 0
     while (Pos <= (this.formula.length-1)) {
          asType = typeChar(formula2.charAt(Pos))
          if ((Pos == 0) && ((asType != 1) && (asType != 5))) {
               alert("Error in Formula at Character " + formula2.charAt(Pos))
          }
          else if (asType == 1) {
               El += 1
               this.elem[El] = formula2.charAt(Pos)
               this.numel[El] = 1
          }
          else if (asType == 2) {
               this.elem[El] += formula2.charAt(Pos)
          }
          else if (asType == 3) {
               Temp = formula2.charAt(Pos)
               this.numel[El] = evalNum(Temp)
          }
          else if ((asType == 4) || (asType == 7)) {
               Temp = formula2.charAt(Pos)
               this.charge = evalNum(Temp)
          }
          else if (asType == 5) {
               StartEl = El + 1
          }
          else if (asType == 6) {
               Temp = 0
               IQ = evalNum(Temp)
               if (IQ == 0) { IQ = 1}
               EndEl = El
               for (var i = StartEl; i <=EndEl; i++) {
                    this.numel[i] *= IQ
               }
          }
          Pos += 1
     }
     this.elem[0] = El
     this.numel[0] = El
}

function wrEqn(Coef) {

   var i = 0
   var temp = ""

   for (i=1;i<=this.numreac;i++) {
      if (Coef == "initial") {
         if (this.rcoefi[i] != 1) {
            temp += this.rcoefi[i]
         }
      }
      else if (Coef == "final") {
         if (this.rcoeff[i] != 1) {
            temp += this.rcoeff[i]
         }
      }
      temp += this.reac[i].formula
      if (i == this.numreac) {
         temp += " --> "
      }
      else {
         temp += " + "
      }
   }
   for (i=1;i<=this.numprod;i++) {
      if (Coef == "initial") {
         if (this.pcoefi[i] != 1) {
            temp += this.pcoefi[i]
         }
      }
      else if (Coef == "final") {
         if (this.pcoeff[i] != 1) {
            temp += this.pcoeff[i]
         }
      }
      temp += this.prod[i].formula
      if (i != this.numprod) {
         temp += " + "
      }
   }
   return temp
}

function fmatEqn(Coef) {

   // Coef = "none", "initial", "final" coefficients
   var i = 0
   var j = 0
   var temp = "<B>"

   for (i=1;i<=this.numreac;i++) {
      if (Coef == "initial") {
         if (this.rcoefi[i] != 1) {
            temp += this.rcoefi[i]
         }
      }
      else if (Coef == "final") {
         if (this.rcoeff[i] != 1) {
            temp += this.rcoeff[i]
         }
      }
      for (j=1;j<=this.reac[i].elem[0];j++) {
         temp += this.reac[i].elem[j]
         if (this.reac[i].numel[j] != 1) {
            temp += "<sub>" + this.reac[i].numel[j] + "</sub>"
         }
      }
      if (this.reac[i].charge != 0) {
         temp += "<sup>"+this.reac[i].charge+"</sup>"
      }
      if (i == this.numreac) {
         temp += " --> "
      }
      else {
         temp += " + "
      }
   }
   for (i=1;i<=this.numprod;i++) {
      if (Coef == "initial") {
         if (this.pcoefi[i] != 1) {
            temp += this.pcoefi[i]
         }
      }
      else if (Coef == "final") {
         if (this.pcoeff[i] != 1) {
            temp += this.pcoeff[i]
         }
      }
      for (j=1;j<=this.prod[i].elem[0];j++) {
         temp += this.prod[i].elem[j]
         if (this.prod[i].numel[j] != 1) {
            temp += "<sub>" + this.prod[i].numel[j] + "</sub>"
         }
      }
      if (this.prod[i].charge != 0) {
         temp += "<sup>"+this.prod[i].charge+"</sup>"
      }
      if (i != this.numprod) {
         temp += " + "
      }
   }
   temp += "</B>"
   return temp
}

function fmatEqn2(Coef) {

   var i = 0
   var temp = "<B>"
   var temp2 = ""
   var asType = 0

   for (i=1;i<=this.numreac;i++) {
      if (Coef == "initial") {
         if (this.rcoefi[i] != 1) {
            temp += this.rcoefi[i]
         }
      }
      else if (Coef == "final") {
         if (this.rcoeff[i] != 1) {
            temp += this.rcoeff[i]
         }
      }
      formula2 = this.reac[i].formula
      Pos = 0
      while (Pos <= (formula2.length - 1)) {
         asType = typeChar(formula2.charAt(Pos))
         if ((asType == 4)||(asType == 7)) {
            temp+= "<sup>"+formula2.charAt(Pos)
            Pos += 1
            temp2 = formula2.charAt(Pos)
            temp += Math.abs(evalNum(temp2)) + "</sup>"
         }
         else if (asType == 3) {
            temp2 = formula2.charAt(Pos)
            temp += "<sub>" + evalNum(temp2) + "</sub>"
         }
         else {
            temp += formula2.charAt(Pos)
         }
         Pos += 1
      }
      if (i == this.numreac) {
         temp += " --> "
      }
      else {
         temp += " + "
      }
   }
   for (i=1;i<=this.numprod;i++) {
      if (Coef == "initial") {
         if (this.pcoefi[i] != 1) {
            temp += this.pcoefi[i]
         }
      }
      else if (Coef == "final") {
         if (this.pcoeff[i] != 1) {
            temp += this.pcoeff[i]
         }
      }
      formula2 = this.prod[i].formula
      Pos = 0
      while (Pos <= (formula2.length - 1)) {
         asType = typeChar(formula2.charAt(Pos))
         if ((asType == 4)||(asType == 7)) {
            temp+= "<sup>"+formula2.charAt(Pos)
            Pos += 1
            temp2 = formula2.charAt(Pos)
            temp += Math.abs(evalNum(temp2)) + "</sup>"
         }
         else if (asType == 3) {
            temp2 = formula2.charAt(Pos)
            temp += "<sub>" + evalNum(temp2) + "</sub>"
         }
         else {
            temp += formula2.charAt(Pos)
         }
         Pos += 1
      }
      if (i != this.numprod) {
         temp += " + "
      }
   }
   temp += "</B>"
   return temp
}

function getRxeqwt() {

   var i = 0

   for (i=1;i<=this.numreac;i++) {
      if (this.reac[i].molwt==0) {
         this.reac[i].getMolwt()
      }
      if (this.rcoeff[i]!=0) {
         this.rxeqwt[i]=this.reac[i].molwt*this.rcoeff[i]
      }
      else if (this.rcoefi[i]!=0) {
         this.rxeqwt[i]=this.reac[i].molwt*this.rcoefi[i]
      }
   }
   for (i=1;i<=this.numprod;i++) {
      if (this.prod[i].molwt==0) {
         this.prod[i].getMolwt()
      }
      if (this.pcoeff[i]!=0) {
         this.rxeqwt[i+this.numreac]= -this.prod[i].molwt*this.pcoeff[i]
      }
      else if (this.pcoefi[i]!=0) {
         this.rxeqwt[i+this.numreac]=this.prod[i].molwt*this.pcoefi[i]
      }
   }
}

function getRxnamt() {

   var i = 0

   for (i=1;i<=this.numreac;i++) {
      this.rxnamt[i]=this.reac[i].gamt/this.rxeqwt[i]
   }
   for (i=1;i<=this.numprod;i++) {
      this.rxnamt[i+this.numreac]=this.prod[i].gamt/this.rxeqwt[i+this.numreac]
   }
}

function getRxnlim() {

   var min = 1.0e6

   for (var i=1;i <= this.numreac;i++) {
      if (this.rxnamt[i] < min) {
         min = this.rxnamt[i]
      }
   }
   this.rxnamt[0] = min
   for (i=1;i<=this.numreac;i++) {
      this.reac[i].gamt -= min*this.rxeqwt[i]
   }
   for (i=1;i<=this.numprod;i++) {
      this.prod[i].gamt += min*this.rxeqwt[i + this.numreac]
   }
}

function wrfMat() {

   var temp = "\r"

   for (var i=1;i<=this.numtotl;i++) {
      for (var j=1;j<=this.numtotl;j++) {
         temp += fMatrix[i][j] + "  "
      }
      temp += "\r"
   }
   return temp
}

function parsEqn(){

     // Uses Global variables equat2 and EPos

     var flag = "R"
     var currnum = 1
     var numreac = 1
     var numprod = 0
     var asType = 0
     var q = 0
     equat2 = this.equation + " "
     EPos = 0
     while (EPos <= (equat2.length-1)) {
          asType = typeChar(equat2.charAt(EPos))
          if ((asType == 1)||(asType == 5)||((asType ==2)
             && (equat2.charAt(EPos) == "e"))) {
               q = equat2.indexOf(" ",EPos)
               if (q > EPos) {
                  if (flag == "R") {
                     this.reac[numreac] = 
                       new substance(" ",equat2.substring(EPos,q),0,0,0,0,0)
                     this.rcoefi[numreac] = currnum
                     this.rcoeff[numreac] = 0
                     currnum = 1
                     EPos = q
                  }
                  else if (flag == "P") {
                     this.prod[numprod] = 
                       new substance(" ",equat2.substring(EPos,q),0,0,0,0,0)
                     this.pcoefi[numprod] = currnum
                     this.pcoeff[numprod] = 0
                     currnum = 1
                     EPos = q
                  }
                  else {
                  }
               }
          }
          else if (asType == 3) {
               Temp = equat2.charAt(EPos)
               currnum = evalEnum(Temp)
          }
          else if (asType == 10) {
          }
          else if (EPos == 0) {
               alert("Error in Formula at Character " + equat2.charAt(EPos))
          }
          else if (asType == 4) {
               if (flag == "R") {
                    numreac += 1
               }
               else if (flag == "P") {
                    numprod += 1
               }
               else {
               }
          }
          else if (asType == 7) {
          }
          else if ((asType == 8) || (asType == 9)) {
               flag = "P"
               numprod = 1
          }
          else {
          }
          EPos += 1
     }
     this.numreac = numreac
     this.numprod = numprod
     this.numtotl = numreac + numprod
}

function getElem() {

     var i = 0
     var j = 0
     var k = 0
     var flag = false
     var elemlist = new Array()

     // Parse formulas of all reactants and products

     for (i = 1; i <= this.numreac; i++) {
          this.reac[i].parsForm()
     }
     for (i = 1; i <= this.numprod; i++) {
          this.prod[i].parsForm()
     }

     // List all elements in reactants
     
     elemlist[0] = " "

     for (i = 1; i <= this.numreac; i++) {
          for (j = 1; j <= this.reac[i].elem[0]; j++) {
               k = 1
               flag = false
               while ((k <= elemlist.length) && (flag == false)) {
                    if (this.reac[i].elem[j] == elemlist[k-1]) {
                         flag = true
                    }
                    k += 1
               }
               if (flag == false) {
                    k = elemlist.length + 1
                    elemlist[k-1] = this.reac[i].elem[j]
               }
               if (this.reac[i].charge != 0) {
                    this.charged = true
               }
          }
     }
     this.elemlist = elemlist
}

function normCol(j,n) {

     // Uses Global variable fMatrix

     var s = 0
     var s1 = 0
     var sr = 0
     var i = 0

     for (i = 1; i <= n; i++) {
          s1 += fMatrix[i][j] * fMatrix[i][j]
     }

     sr = Math.sqrt(s1)
     if (s1 < 1e-7) {
          for (i = 1; i <= n; i++) {
               fMatrix[i][j] = 0
          }
          s1 = 0
     }
     else {
          for (i = 1; i <= n; i++) {
               fMatrix[i][j] /= sr
          }
     }
     s = s1
     return s
}

function proJect(j,k,n) {

     // Uses Global variable fMatrix

     var t = 0
     var i = 0

     for (i = 1; i <= n; i++) {
          t += fMatrix[i][j] * fMatrix[i][k]
     }
     for (i = 1; i <= n; i++) {
          fMatrix[i][k] -= t * fMatrix[i][j]
     }
}

function findMax(list) {

     var max = 0

     for (var i = 1;i < list.length; i++) {
          if (list[i] > max) {
               max = list[i]
          }
     }
     return max
}

function factor(r,res) {

     var q = 0
     var flag = false
     var rlist = new Array()
     var slist = new Array()
     var imax = 1

     rlist[imax] = r
     while (flag == false) {
          slist[imax] = rlist[imax] - Math.floor(rlist[imax])
          if (slist[imax] > 0.5) {
               slist[imax] = 1 - slist[imax]
          }
          if (slist[imax] < res) {
               flag = true
          }
          else {
               imax += 1
               rlist[imax] = 1/slist[imax - 1]
          }
     }
     q = 1
     if (imax > 1) {
          for (i = 2; i <= imax; i++) {
               q *= rlist[i]
          }
     }
     // p = rlist[1] * q
     // p = Math.round(p)
     q = Math.round(q)
     // return p
     return q
}



function balEqn() {

// Uses Global variable fMatrix

// Local variables
     var n = this.numtotl
     var m = this.elemlist.length - 1
     var mprime = m
     var r = 0
     var s = 0
     var i = 0
     var j = 0
     var k = 0
     var flag = false
     var Coeff = new Array()
     var absCoeff = new Array()
     var maxCoeff = 0

     // n is total number of species (reactants and products)
     // m is number of constituents (elements, groups, or the net 
     //   charge of a species)

     // If any species are charged, add to value of m

     if (this.charged) {m += 1}

     // Set up matrix

     for (i = 1; i <= n; i++) {
          fMatrix[i] = new Array()
          for (j = 1; j <= n + m; j++) {
               fMatrix[i][j] = 0
          }
     }

     // Add number of each element in each species to fMatrix

     for (i = 1; i <= this.numreac; i++) {
          for (j = 1; j <= this.reac[i].elem[0]; j++) {
               k = 1
               flag = false
               while ((k <= this.elemlist.length) && (flag == false)) {
                    if (this.reac[i].elem[j] == this.elemlist[k-1]) {
                         flag = true
                         fMatrix[i][k-1] = this.reac[i].numel[j]
                    }
                    k += 1
               }
               if (flag == false) {
                    k = this.elemlist.length + 1
                    this.elemlist[k-1] = this.reac[i].elem[j]
                    fMatrix[i][k-1] = this.reac[i].numel[j]
               }
          }
     }
     for (i = 1; i <= this.numprod; i++) {
          for (j = 1; j <= this.prod[i].elem[0]; j++) {
               k = 1
               flag = false
               while ((k <= this.elemlist.length) && (flag == false)) {
                    if (this.prod[i].elem[j] == this.elemlist[k-1]) {
                         flag = true
                         fMatrix[i + this.numreac][k-1] = this.prod[i].numel[j]
                    }
                    k += 1
               }
               if (flag == false) {
                    k = this.elemlist.length + 1
                    this.elemlist[k-1] = this.prod[i].elem[j]
                    fMatrix[i + this.numreac][k-1] = this.prod[i].numel[j]
               }
          }
     }

     // Add charges (if any)

     if (this.charged) {
          for (i = 1; i <= this.numreac; i++) {
               fMatrix[i][m] = this.reac[i].charge
          }
          for (i = 1; i <= this.numprod; i++) {
               fMatrix[i + this.numreac][m] = this.prod[i].charge
          }
     }
     // Augment fMatrix of n rows and m columns to an n x n matrix

     for (i = 1; i <= n; i++) {
          for (j = 1; j <= n; j++) {
               if (i == j) {fMatrix[i][m + j] = 1}
               else {fMatrix[i][m + j] = 0}
          }
     }
     //Gram-Schmidt routine

     mprime = m
     s = normCol(1,n)
     k = 2
     while (k <= n) {
          for (j = 1; j <= k - 1; j++) {
               proJect(j,k,n)
          }
          s = normCol(k,n)
          if (s < 1e-7) {
               for (j = k; j <= n + mprime - 1; j++) {
                    for (i = 1; i <= n; i++) {
                         fMatrix[i][j] = fMatrix[i][j+1]
                    }
               }
               j = n + mprime
               for (i = 1; i <= n; i++) {
                    fMatrix[i][j] = 0
               }
               if (k <= mprime) {
                    mprime -= 1
               }
          }
          else { 
               k += 1
          }
     }
     r = n - mprime

     if (r != 1) {
        alert("Not a valid equation: cannot be balanced or no unique solution!")
        trouble = true
     }
     if (!trouble) {
        // Convert Coefficients to Integers
        //     The reaction vector is in column mprime+1 of fMatrix
        var col = mprime + 1
     
        for (j = 1; j <= n; j++) {
             Coeff[j] = fMatrix[j][col]
             absCoeff[j] = Math.abs(Coeff[j])
        }
        maxCoeff = findMax(absCoeff)

        for (j = 1; j <= n; j++) {
             Coeff[j] /= maxCoeff
        }
        for (j = 1; j <= n; j++) {
             fac = factor(Math.abs(Coeff[j]), 0.1)
             for (i = 1; i <= n; i++) {
                  Coeff[i] *= fac
             }
        }
        for (i = 1; i <= this.numreac; i++) {
             this.rcoeff[i] = Math.round(Coeff[i])
        }
        for (i = 1; i <= this.numprod; i++) {
             this.pcoeff[i] = Math.round(Coeff[i + this.numreac])
        }
     }
}

// DEFINE OBJECTS

function substance(name,formula,charge,molwt,shape,gamt,chemamt) {

     // To define: enter name (or "") and formula; enter 0 for parameters 
     //            which can be calculated by methods (charge, molwt,
     //            shape,chemamt);mass in grams may be entered for gamt
     //            or gamt may be set to 0 and calculated in script)

     this.name = name
     this.formula = formula
     this.charge = charge
     this.molwt = molwt
     this.shape = shape
     this.gamt = gamt
     this.chemamt = chemamt
     this.elem = new Array()
     this.numel = new Array()
     this.parsForm = parsForm
     this.getMolwt = getMolwt
     this.getShape = getShape
     this.binName = binName
     this.wrFormula = wrFormula
     this.fmatForm = fmatForm
}

function reaction(equation,typereac,numreac,numprod,numtotl,charged) {

     // To define: enter equation; typereac may be entered or set to 0;
     //            enter 0 for other parameters (which can be 
     //            calculated by the objects methods) except charged,
     //            which should be set to false.

     this.equation = equation
     this.typereac = typereac
     this.numreac = numreac
     this.numprod = numprod
     this.numtotl = numtotl
     this.charged = charged
     this.reac = new Array()
     this.rcoeff = new Array()
     this.rcoefi = new Array()
     this.prod = new Array()
     this.pcoeff = new Array()
     this.pcoefi = new Array()
     this.elemlist = new Array()
     this.rxeqwt = new Array()
     this.rxnamt = new Array()
     this.parsEqn = parsEqn
     this.getElem = getElem
     this.balEqn = balEqn
     this.wrEqn = wrEqn
     this.fmatEqn = fmatEqn
     this.fmatEqn2 = fmatEqn2
     this.getRxeqwt = getRxeqwt
     this.getRxnamt = getRxnamt
     this.getRxnlim = getRxnlim
     this.wrfMat = wrfMat
}

// STOP HIDING FROM OTHER BROWSERS -->
