/*
Xml reserve caracter
& --> &amp;
< --> &lt;
> --> &gt;

Common special html caracter inside xml/dom
  --> &nbsp; (in html) == &#160; (in xml/dom)

See full list of special html/xml caracter at:
  http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html

*/

//////////////////////////////////////////////////////////////
//                    BROWSER PROPERTY                      //
//////////////////////////////////////////////////////////////
var browser = new Browser();

function Browser() {
  var ua = navigator.userAgent.toLowerCase(); 

  // browser engine name
  this.isGecko       = (ua.indexOf('gecko') != -1 && ua.indexOf('safari') == -1);
  this.isKonqueror   = (ua.indexOf('konqueror') != -1); 
  this.isSafari      = (ua.indexOf('safari') != - 1);
  this.isOmniweb     = (ua.indexOf('omniweb') != - 1);
  this.isOpera       = (ua.indexOf('opera') != -1); 
  this.isIcab        = (ua.indexOf('icab') != -1); 
  this.isAol         = (ua.indexOf('aol') != -1); 
  this.isIE          = (ua.indexOf('msie') != -1 && !this.isOpera && (ua.indexOf('webtv') == -1) ); 
  this.isMozilla     = (this.isGecko && ua.indexOf('gecko/') + 14 == ua.length);
  this.isFirefox     = (ua.indexOf('firefox/') != -1 || ua.indexOf('firebird/') != -1);
  this.isNS          = ( (this.isGecko) ? (ua.indexOf('netscape') != -1) : ( (ua.indexOf('mozilla') != -1) && !this.isOpera && !this.isSafari && (ua.indexOf('spoofer') == -1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('webtv') == -1) && (ua.indexOf('hotjava') == -1) ) );

  // Supersede all other browser
  if(!this.isIE) { this.isGecko = 1; }  
}
/*
EXAMPLE :
  if(browser.isIE) {
    // Ie code here
  }
  if(browser.isGecko) {
    // Gecko code here
  }
  
  (browser.isIE) ? oEle.add(oOption) : oEle.appendChild(oOption);
*/

//////////////////////////////////////////////////////////////
//           AJAX OBJECT (by Patrick Hunlock)               //
//////////////////////////////////////////////////////////////
function AjaxObject(url, callbackFunction) {
  var that = this;
  this.updating = false;
  
  this.abort = function() {
    if(that.updating) {
      that.updating = false;
      that.AJAX.abort();
      that.AJAX = null;
    }
  }
  
  this.update = function(passData, postMethod) {
    if(that.updating) { return false; }
    that.AJAX = null;
    
    if(window.XMLHttpRequest) {
      that.AJAX = new XMLHttpRequest();
    } else {
        that.AJAX = new ActiveXObject("Microsoft.XMLHTTP");
      }
    
    if(that.AJAX == null) {
      return false;
    } else {
      that.AJAX.onreadystatechange = function() {
        if(that.AJAX.readyState == 4) {
          that.updating = false;
          that.callback(that.AJAX.responseText, that.AJAX.status, that.AJAX.responseXML);
          that.AJAX = null;
        }
      }
      
      that.updating = new Date();
      if(/post/i.test(postMethod)) {
        var uri = urlCall + '?' + that.updating.getTime();
        that.AJAX.open("POST", uri, true);
        that.AJAX.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        that.AJAX.send(passData);
      } else {
          var uri = urlCall + '?' + passData + '&timestamp=' + (that.updating.getTime());
          that.AJAX.open("GET", uri, true);
          that.AJAX.send(null);
        }
      return true;
    }
  }
  var urlCall = url;
  this.callback = callbackFunction || function () {};
}
/*
EXAMPLE :
function fin(responseTxt, responseStat) {
  alert(responseStat +' - '+ responseTxt);
}

var test1 = new AjaxObject('http://localhost/gridwebentry/ajaxReveiver.asp', fin);
    test1.update('id=user4379');

var test2 = new AjaxObject('http://localhost/gridwebentry/ajaxReveiver.asp', fin);
    test2.update('coolData=47&userId=user49&log=true','POST');

var test3 = new AjaxObject('http://localhost/gridwebentry/ajaxReveiver.asp', fin);
    test3.update(xmlDoc, "POST");
*/

//////////////////////////////////////////////////////////////
//                        GECKO ONLY                        //
//////////////////////////////////////////////////////////////
if(browser.isGecko) {
  // DOM, oEle.textContent in Gecko == oEle.innerText in Ie;
  // XML, oNode.textContent in Gecko == oNode.text in Ie;
  
  Object.prototype.xml = function() { return (new XMLSerializer()).serializeToString(this); }
  /*
  EXAMPLE :
    var oTable = document.getElementById("id");
    alert(oTable.xml());
  */
  
  Object.prototype.getElementsByClass = function(searchClass, tag) {      
    var classElements = new Array();
    
    if(tag == null || tag == "") { tag = "*"; }
    
    var elements = this.getElementsByTagName(tag);
    var pattern = new RegExp('(^|\\s)' + searchClass + '(\\s|$)');
    
    var i = 0;
    while(i < elements.length) {
      if(pattern.test(elements[i].className)) {
        classElements.push(elements[i]);
      }
      i++;
    }
    return classElements;
  }
  /*
  EXAMPLE :
    function GetWindows() {
      var oBody = document.body;
      var windows;

      if(browser.isIE) {
        windows = GetElementsByClass("window", oBody, "div");
      }
      else if(browser.isGecko) {
        windows = oBody.getElementsByClass("window","div");
      }

      var i = 0;
      while(i < windows.length) {
        // Your code here ... 
        i++;
      }
    }
  */
  
  // Opera 9 have a native support for xml .selectSingleNode and .selectNodes method
  // but it show some problem on the oNodeList.nextNode and oNodeList.iterateNext() method
  // so we supersede their implementation with the default Gecko browser method with this code line:
  if(typeof XMLDocument == "undefined" ){ XMLDocument = Document; }
  
  // Map namespace resolver (return null if there is no prefix or it is not found)
  function nsResolver(prefix) {
    var ns = {
      'xhtml' : 'http://www.w3.org/1999/xhtml',
      'mathml': 'http://www.w3.org/1998/Math/MathML',
      'email' : 'http://www.mysite.com/email',
      'pub'   : 'http://www.mysite.com/pub'
    };
    return ns[prefix] || null;
  }
  
  XMLDocument.prototype.selectSingleNode = function(xPathQuery, contextNode) {
    if(contextNode) {
      return this.evaluate(xPathQuery, contextNode, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
    } else {
        return this.evaluate(xPathQuery, this, nsResolver, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
      }
  }
  
  Element.prototype.selectSingleNode = function(xPathQuery) {
    return this.ownerDocument.selectSingleNode(xPathQuery, this);
  }
  /*
  EXAMPLE :
    var xPathQuery = "Dataset/Head/Parent";
    var oNodeParent = xmlGrid.selectSingleNode(xPathQuery);
    
    if(oNodeParent) {
      xPathQuery = "./Child1";
      oChild = oNodeParent.selectSingleNode(xPathQuery);
    }
  */
  
  XMLDocument.prototype.selectNodes = function(xPathQuery, snapshot, contextNode) {
    if (snapshot) {
      // To get the length of the node list in test mode (ex: oNodeList.snapshotLength, oNodeList.snapshotItem(i))
      if(contextNode) {
        return this.evaluate(xPathQuery, contextNode, nsResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
      } else {
          return this.evaluate(xPathQuery, this, nsResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
        }
    } else {
        if(contextNode) {
          return this.evaluate(xPathQuery, contextNode, nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
        } else {
            return this.evaluate(xPathQuery, this, nsResolver, XPathResult.ORDERED_NODE_ITERATOR_TYPE, null);
          }
      }
  }
  
  Element.prototype.selectNodes = function(xPathQuery, snapshot) {
    return this.ownerDocument.selectNodes(xPathQuery, snapshot, this);
  }
  /*
  EXAMPLE :
    var xPathQuery = "Dataset/Head/*";
    var oNodeList = xmlDoc.selectNodes(xPathQuery);
    var oNode = (browser.isIE) ? oNodeList.nextNode : oNodeList.iterateNext();
    
    while(oNode) {
      att = oNode.getAttribute("att");
      text = (browser.isIE) ? oNode.text : oNode.textContent;
      
      oNode = (browser.isIE) ? oNodeList.nextNode : oNodeList.iterateNext();
    }
    
    var xPathQuery = "./*";
    var oChilds = oNode.selectNodes(xPathQuery);
    var oNodeTemp = (browser.isIE) ? oChilds.nextNode : oChilds.iterateNext();
  
    while(oNodeTemp) {
      att = oNodeTemp.getAttribute("att");
      text = (browser.isIE) ? oNodeTemp.text : oNodeTemp.textContent;
      
      oNodeTemp = (browser.isIE) ? oChilds.nextNode : oChilds.iterateNext();
    }
  */
}

//////////////////////////////////////////////////////////////
//                  INTERNET EXPLORER ONLY                  //
//////////////////////////////////////////////////////////////
if(browser.isIE) {
  
  function GetElementsByClass(searchClass, node, tag) {
    var classElements = new Array();
    
    if(node == null) { node = document; }
    if(tag == null || tag == "") { tag = "*"; }
    
    var elements = node.getElementsByTagName(tag);
    var pattern = new RegExp('(^|\\s)' + searchClass + '(\\s|$)');
    
    var i = 0;
    while(i < elements.length) {
      if(pattern.test(elements[i].className)) {
        classElements.push(elements[i]);
      }
      i++;
    }
    return classElements;
  }
  /*
  EXAMPLE :
    function GetWindows() {
      var oBody = document.body;
      var windows;

      if(browser.isIE) {
        windows = GetElementsByClass("window", oBody, "div");
      }
      else if(browser.isGecko) {
        windows = oBody.getElementsByClass("window","div");
      }

      var i = 0;
      while(i < windows.length) {
        // Your code here ... 
        i++;
      }
    }
  */
  
  function ConvertIeDomToDHTML(oNode) {
    // Serialize Ie DOM to XML for parser
    // Convert Ie html DOM node to XML format

    // Check if node is past as reference or text value
    var text = (oNode.outerHTML) ? oNode.outerHTML : oNode;
    
    var reg;
    var arrMatch;
    var position;
    var ptyName;
    var ptyValue;
    var replacer;
    
    // Replace all htm common node property (most common use, this list is not exhaustive)
    var arrPty = new Array("id", "class", "onclick", "onkeydown", "onkeypress", "onkeyup", "ondblclick", 
                           "onmousedown", "onmousemove", "onmouseout", "onmouseover", "onmouseup", 
                           "onchange", "onkeypress", "alt", "align", "accesskey", "onfocus", 
                           "title", "cellspacing", "cellpadding", "border", "rows", "cols", "target", 
                           "maxlength", "name", "size", "type", "value", "color", "width", "height");
    
    var i = 0;
    var j;
    while(i < arrPty.length) {
      reg = new RegExp(arrPty[i] + "=([\\w\\(\\)\\[\\]'.#|;-]+)", "gi");
      arrMatch = text.match(reg);
      if(arrMatch != null) {
        j = 0;
        while(j < arrMatch.length) {
          // Add apostrophe caracter to property value
          position = arrMatch[j].indexOf("=");
          ptyName = arrMatch[j].substring(0, position);
          ptyValue = arrMatch[j].substring(position + 1);
          
          replacer = ptyName + "=\"" + ptyValue + "\"";
          text = text.replace(arrMatch[j], replacer);
          j++;
        }
      }
      i++;
    }
    
    // Replace single htm marker - value (GridMarshall specific)
    reg = new RegExp("(\" value )", "gi");
    replacer = "\" value=\"\" ";
    text = text.replace(reg, replacer);
    
    // Replace single htm marker - originalvalue (GridMarshall specific)
    reg = new RegExp("(\" originalvalue )", "gi");
    replacer = "\" originalvalue=\"\" ";
    text = text.replace(reg, replacer);
    
    // Replace single htm marker - value & originalvalue - INPUT and TD
    // Ie convert the '&' automatically but not the "<" ">" inside it's property.
    var bTest;
    var typeText;
    var typePosition;
    arrPty = new Array("value", "originalvalue");
    
    i = 0;
    while(i < arrPty.length) {
      reg = new RegExp("( " + arrPty[i] + ")=(.+?)(\")", "gi");
      arrMatch = text.match(reg);
      if(arrMatch != null) {
        j = 0;
        while(j < arrMatch.length) {
          bTest = false;
          typeText = arrMatch[j];
          
          typePosition = typeText.indexOf("<");
          if(typePosition > -1) {
            typeText = typeText.replace(/\x3C/gi, "&lt;");
            bTest = true;
          }
          typePosition = typeText.indexOf(">");
          if(typePosition > -1) {
            typeText = typeText.replace(/\x3E/gi, "&gt;");
            bTest = true;
          }
          
          if(bTest) { text = text.replace(arrMatch[j], typeText); }
          j++;
        }
      }
      i++;
    }
    
    // Replace single htm marker - selected
    reg = new RegExp("(\" selected)", "gi");
    replacer = "\" selected=\"selected\"";
    text = text.replace(reg, replacer);
    
    // Replace single htm marker - checked
    reg = new RegExp("(\" checked)", "gi");
    replacer = "\" checked=\"checked\"";
    text = text.replace(reg, replacer);
    
    // Replace single htm marker - disabled
    reg = new RegExp("( disabled)", "gi");
    replacer = " disabled=\"disabled\"";
    text = text.replace(reg, replacer);
    
    // Replace single htm marker - BR
    reg = new RegExp("(<BR>)", "gi");
    replacer = "<BR />";
    text = text.replace(reg, replacer);
    
    // Replace single htm marker - &nbsp;
    reg = new RegExp("(&nbsp;)", "gi");
    replacer = " ";
    text = text.replace(reg, replacer);
    
    // Replace single htm marker - HR
    reg = new RegExp("<HR" + "(.*)" + ">", "gi");
    arrMatch = text.match(reg);
    if(arrMatch != null) {
      j = 0;
      while(j < arrMatch.length) {
        // Add front slash caracter to property value
        position = arrMatch[j].indexOf(">");
        ptyName = arrMatch[j].substring(0, position);
        ptyValue = arrMatch[j].substring(position);
        
        replacer = ptyName + " /" + ptyValue;
        text = text.replace(arrMatch[j], replacer);
        j++;
      }
    }
    
    // Replace single htm marker - INPUT
    // Some Ie version change the 'type="text"' expression into something like
    // this: {95919BE0-C436-4eab-8083-096E94826667}="input text value"
    var regIeEx = new RegExp("({)(.+?)(})=(.+?)(\")", "gi");
    var regIeExEmpty = new RegExp("({)(.+?)(})", "gi");
    var arrMatchIeEx;
    
    reg = new RegExp("<(INPUT)\\s+?(.+?)\">", "gi");
    arrMatch = text.match(reg);
    if(arrMatch != null) {
      j = 0;
      while(j < arrMatch.length) {
        typeText = arrMatch[j];
        
        arrMatchIeEx = typeText.match(regIeEx);
        if(arrMatchIeEx != null) {
          typeText = typeText.replace(arrMatchIeEx[0], "type=\"text\"");
        }
        arrMatchIeEx = typeText.match(regIeExEmpty);
        if(arrMatchIeEx != null) {
          typeText = typeText.replace(arrMatchIeEx[0], "type=\"text\"");
        }
        
        position = typeText.indexOf(">");
        ptyName = typeText.substring(0, position);
        ptyValue = typeText.substring(position);
        replacer = ptyName + " /" + ptyValue;
        
        text = text.replace(arrMatch[j], replacer);
        j++;
      }
    }
    
    // Replace single htm marker - IMG
    reg = new RegExp("<(IMG)\\s+?(.+?)>", "gi");
    arrMatch = text.match(reg);
    if(arrMatch != null) {
      j = 0;
      while(j < arrMatch.length) {
        // Add front slash caracter to property value
        position = arrMatch[j].indexOf(">");
        ptyName = arrMatch[j].substring(0, position);
        ptyValue = arrMatch[j].substring(position);
        
        replacer = ptyName + " /" + ptyValue;
        text = text.replace(arrMatch[j], replacer);
        j++;
      }
    }
    
    return text;
  }
  /*
  EXAMPLE :
    var oBody = document.body;
    var xmlString = ConvertIeDomToDHTML(oBody);
    var xmlDoc = CreateXmlDoc(xmlString);
  */
}

//////////////////////////////////////////////////////////////
//                     XML DOM OBJECT                       //
//////////////////////////////////////////////////////////////
function GetXmlDomObject() {
  var xmlDoc;
  if(browser.isIE) { 
    xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); 
    xmlDoc.async = false;
    xmlDoc.setProperty("SelectionLanguage", "XPath");
    xmlDoc.validateOnParse = true;
    xmlDoc.preserveWhiteSpace = false;
    
    // Namespace resolver
    var nameSpace = "xmlns:email='http://site1.com' xmlns:pub='http://site2.com'";
    xmlDoc.setProperty("SelectionNamespaces", nameSpace);
    return xmlDoc;
  }
  else if(browser.isGecko) { 
    // Firefox | Netscape | Safari
    xmlDoc = document.implementation.createDocument("", "", null);
    xmlDoc.async = false;
    xmlDoc.validateOnParse = true;
    
    // Safari create a DOM document instead of a XML document
    if(browser.isSafari) { xmlDoc.load = SafariXmlLoad; }
    
    return xmlDoc;
  }
  else { 
    alert("You browser don't support xml document. The page may not behave as expected."); 
    return null; 
  }
}

function SafariXmlLoad(path) {
  if(window.XMLHttpRequest) {
    var request = new XMLHttpRequest();
    request.open("GET", path, false);
    request.send(null);
    return request.responseXML;    
  }
}

function RenderXmlXsl(xmlDoc, xslFile, arrParameter) {
  
  if(browser.isIE) {
    var xslDoc = new ActiveXObject("MSXML2.FreeThreadedDOMDocument");
    xslDoc.async = false;
    xslDoc.load(xslFile.trim());
    
    var xslTemplate = new ActiveXObject("MSXML2.XSLTemplate");
    xslTemplate.stylesheet = xslDoc;
    
    var xsltProcessor = xslTemplate.createProcessor();
    xsltProcessor.input = xmlDoc;
    
    for (var oPara in arrParameter) {
      if(typeof arrParameter[oPara] != "function") {
        xsltProcessor.addParameter(oPara, arrParameter[oPara]);
      }
    }
    
    xsltProcessor.transform();
    return xsltProcessor.output;
  }
  
  if(browser.isGecko) {
    var xslDoc = GetXmlDomObject();
    
    if(!browser.isSafari) {
      xslDoc.load(xslFile.trim());
    } else { xslDoc = xslDoc.load(xslFile.trim()); }
    
    var xsltProcessor = new XSLTProcessor();
    xsltProcessor.importStylesheet(xslDoc);
    
    for (var oPara in arrParameter) {
      if(typeof arrParameter[oPara] != "function") {
        xsltProcessor.setParameter(null, oPara, arrParameter[oPara]);
      }
    }
    
    var d = document.implementation.createDocument("", "", null);
    var oFragment = xsltProcessor.transformToFragment(xmlDoc, d); // (xmlDoc, document)
    return oFragment;
  }
}

function GetXmlDoc(xmlFile) {
  var xmlDoc = GetXmlDomObject();
  
  if(!browser.isSafari) {
    xmlDoc.load(xmlFile.trim());
  } else {
      xmlDoc = xmlDoc.load(xmlFile.trim());
    }
  return xmlDoc;
}

function CreateXmlDoc(text) {
  var xmlDoc;
  
  if(browser.isIE) {
    xmlDoc = GetXmlDomObject();
    xmlDoc.loadXML(text.trim());
  }
  if(browser.isGecko) {
    var parser = new DOMParser();
    xmlDoc = parser.parseFromString(text, "text/xml");
  }
  return xmlDoc;
}

function MakeXmlDocument(text) {
  return "<?xml version=\"1.0\" encoding=\"utf-8\"?><Dataset>" + text + "</Dataset>";
}

function MakeNode(nodeName, nodeText) {
  return "<" + nodeName + ">" + nodeText + "</" + nodeName + ">";
}

//////////////////////////////////////////////////////////////
//                   ADD/REMOVE  EVENT                      //
//////////////////////////////////////////////////////////////
function AddEvent(oEle, evType, fn, useCapture) {
  if (oEle.addEventListener) {
    oEle.addEventListener(evType, fn, useCapture);
    return true;
  }
  else if (oEle.attachEvent) {
    var r = oEle.attachEvent('on' + evType, fn);
    return r;
  }
  else {
    oEle['on' + evType] = fn;
  }
}
/*
EXAMPLE :
  AddEvent(window,'load',func1,false);
*/

function RemoveEvent(oEle, evType, fn, useCapture){
  if (oEle.removeEventListener){
    oEle.removeEventListener(evType, fn, useCapture);
    return true;
  }
  else if (oEle.detachEvent){
    var r = oEle.detachEvent("on"+evType, fn);
    return r;
  }
  else {
    oEle['on' + evType] = null;
  }
} 
/*
EXAMPLE :
  RemoveEvent(window,'load',func1,false);
*/

//////////////////////////////////////////////////////////////
//                    READ CSS PROPERTY                     //
//////////////////////////////////////////////////////////////
function FindStyleRule(styleName) {
  var oCssRules;
  
  var j;
  var i = 0;
  while(i < document.styleSheets.length) {
    var oCssRules = document.styleSheets[i].cssRules || document.styleSheets[i].rules;
    
    j = 0;
    while(j < oCssRules.length) {
      if (oCssRules(j).selectorText == styleName) {
        return oCssRules(j);
      }
      j++;
    }
    i++;
  }
  return null;
}
/*
EXAMPLE :
  var oCssStyle = FindStyleRule(".titleBar");
  var top = oCssStyle.style.top;
  var left = oCssStyle.style.left;
  var height = oCssStyle.style.height;
*/

//////////////////////////////////////////////////////////////
//                    SHOW/HIDE ELEMENT                     //
//////////////////////////////////////////////////////////////
function Toggle(oEle) {
  if (oEle.style.display != "none") {
    oEle.style.display = "none";
  } else {
      oEle.style.display = "";
    }
}
/*
EXAMPLE :
  var oEle = document.getElementById("id");
  Toggle(oEle);
*/

//////////////////////////////////////////////////////////////
//                DOM INSERT ELEMENT AFTER                  //
//////////////////////////////////////////////////////////////
function InsertAfter(newNode, refNode) {

  //var parent = refNode.parentNode;
  var parent = (browser.isIE) ? refNode.parentElement : refNode.parentNode;
  
  if(parent.lastChild == refNode) {
    return parent.appendChild(newNode);
  } else {
      return parent.insertBefore(newNode, refNode.nextSibling);
    }
}
/*
EXAMPLE :
  var oTable = document.getElementById("id");
  var oTBody = oTable.tBodies[0];
  var oRows = oTBody.rows;
  var index = 2;

  InsertAfter(oRows[index], oRows[index + 1]);
*/

//////////////////////////////////////////////////////////////
//                     ARRAY PROTOTYPE                      //
//////////////////////////////////////////////////////////////
Array.prototype.find = function(searchStr) {
  var returnArray = false;
  
  var i = 0;
  while(i < this.length) {
    if(typeof(searchStr) == 'function') {
      if(searchStr.test(this[i])) {
        if (!returnArray) { returnArray = [] }
        returnArray.push(i);
      }
    } else {
        if(this[i]===searchStr) {
          if(!returnArray) { returnArray = [] }
          returnArray.push(i);
        }
      }
    i++;
  }
  
  return returnArray;
}
/*
EXAMPLE :
  var tmp = [5,9,12,18,56,1,10,42,'blue',30, 7,97,53,33,30,35,27,30,'35','Ball', 'bubble'];
  var thirty = tmp.find(30); // Returns 9, 14, 17
  var thirtyfive = tmp.find('35'); // Returns 18
  var thirtyfive = tmp.find(35); // Returns 15
  var haveBlue = tmp.find('blue'); // Returns 8
  var notFound = tmp.find('not there!'); // Returns false
  var regexp1 = tmp.find(/^b/); // returns 8,20 (first letter starts with b)
  var regexp1 = tmp.find(/^b/i); // returns 8,19,20 (same as above but ignore case)
*/

Array.prototype.shuffle = function() {
  this.sort(function(a,b) { return random(2); })
}

Array.prototype.sortNum = function() {
  return this.sort(function(a,b) { return a-b; } );
}

Array.prototype.indexOf = function(vItem) {
  var i = 0;
  while(i < this.length) {
    if(vItem === this[i]) { return i; }
    i++;
  }
  return -1;
}

//////////////////////////////////////////////////////////////
//                        IS ARRAY                          //
//////////////////////////////////////////////////////////////
Object.prototype.isArray = function() {
  return this.constructor == Array;
}
/*
EXAMPLE :
  alert([].isArray()); // output true
  alert({}.isArray()); // output false
*/

//////////////////////////////////////////////////////////////
//                     STRING PROTOTYPE                     //
//////////////////////////////////////////////////////////////
String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g,""); }
String.prototype.ltrim = function() { return this.replace(/^\s+/g,""); }
String.prototype.rtrim = function() { return this.replace(/\s+$/g,""); }

String.prototype.htmlEntities = function () {
  return this.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
/*
EXAMPLE :
  var tmp = '<html><head></head>';
  var safe= tmp.htmlEntities(); // Returns “&lt;html&gt;&lt;head&gt;&lt;/head&gt;”
*/

String.prototype.stripTags = function () {
  return this.replace(/<([^>]+)>/g,'');
}
/*
EXAMPLE :
  var tmp = '<a href="http://somespammer.com">Some Link</a>';
  var safe= tmp.stripTags(); // Returns 'Some Link';
*/

String.prototype.replace = function(pattern, replacement) {
  return this.split(pattern).join(replacement);
}
/*
EXAMPLE :
  var str = "hello world";
  var newstr = str.replace("world", "you");
*/

//////////////////////////////////////////////////////////////
//                   ACCESSORY FUNCTION                     //
//////////////////////////////////////////////////////////////
function ShadeTableBody(oTBody, rowGap, color) {
  if(!rowGap) { rowGap = 2; }
  if(!color) { color = "#E2E2E2"; } // light gray
  
  var oRows = oTBody.rows;
  var oRow = null;
  
  i = 0;
  while(i < oRows.length) {
    oRows[i].className = "";
    if((i + 1) % rowGap == 0) {
      if(i > 0) {
        oRows[i].style.backgroundColor = color;
      } else {oRows[i].style.backgroundColor = "";}
    } else {oRows[i].style.backgroundColor = "";}
    i++;
  }
}
/*
EXAMPLE :
  var oTable = document.getElementById("id");
  var oTBody = oTable.tBodies[0];
  ShadeTableBody(oTBody);
*/

function GetParentTagName(oEle, tagName) {
  var oParent = oEle;
  
  while(oParent.tagName.toLowerCase() != tagName.toLowerCase()) {
    oParent = (browser.isIE) ? oParent.parentElement : oParent.parentNode;
    if(oParent.tagName.toLowerCase() == "body") { return null; }
  }
  return oParent;
}
/*
EXAMPLE :
  <TABLE>
    <TR>
      <TD>
        <a href="http://yousite.com" onclick="Demo(this);">Link</a>
      </TD>
    </TR>
  </TABLE>
  
  function Demo(oEle) {
    var oTable = GetParentTagName(oEle, "TABLE");
  }
*/

function GetGUID() {
  return Math.round(Math.random() * 1000000000) % 1000000000;
}
/*
EXAMPLE :
  var uniqueID = GetGUID();
*/

function GetRandomInt(maxNum) {
  var ranNum;
  
  if(Math.random && Math.round) {
    ranNum = Math.round(Math.random() * (maxNum - 1)) + 1;
    return ranNum;
  }
}

function StatusBarWrite(str, i) {
  window.status = str;
  window.setTimeout("window.status = \"\";", i);
}
/*
EXAMPLE :
  function Demo() {
    try {
      // Code here
    } catch(e) { 
      StatusBarWrite("Error (fnc : " + "Demo" + "). " + e.message, 3000);
    }
  }
*/

function GetDocumentWidth() {
  var width = (browser.isIE) ? document.body.clientWidth : document.body.offsetWidth;
  return width - 7;
}
/*
EXAMPLE :
  var width = GetDocumentWidth();
*/

function GetDocumentHeight() {
  var height = (browser.isIE) ? document.body.clientHeight : document.body.offsetHeight;
  return height - 7;
}
/*
EXAMPLE :
  var height = GetDocumentHeight();
*/

function GetXOffset(evt) {
  if(typeof evt.offsetX != 'undefined') {
    return evt.offsetX;
  }
  else if(typeof evt.pageX != 'undefined') {
    return evt.pageX - evt.target.offsetLeft;
  }
}

function GetYOffset(evt) {
  if(typeof evt.offsetY != 'undefined') {
    return evt.offsetY;
  }
  else if(typeof evt.pageY != 'undefined') {
    return evt.pageY - evt.target.offsetTop;
  }
}
/*
EXAMPLE :
  function DisplayOffsets(e) {
    var evt = (evt) ? evt : window.event;
    window.status = 'x: ' + GetXOffset(evt) + ' y: ' + GetYOffset(evt);
  }
  
  <div id="sample" onmousemove="DisplayOffsets(event)">Text Offsets X and Y</div>
*/

function FormatNumber(num, decimalNum, bolLeadingZero, bolParens, bolCommas, trailDecimal, prefix) {
/**********************************************************************
  Original by www.4guysfromrolla.com, modify by Developer Utility
  
	IN:
		NUM            - the number to format
		decimalNum     - the number of decimal places to format the number to
		bolLeadingZero - true / false - display a leading zero for numbers between -1 and 1
		bolParens      - true / false - use parenthesis around negative numbers
		bolCommas      - put commas as number separators
    trailDecimal   - number of decimal show
		prefix         - symbol to add with formating
 **********************************************************************/

  if (isNaN(parseInt(num))) return "NaN";

	var tmpNum = num;
	var iSign = num < 0 ? -1 : 1;		// Get sign of number
	
	// Adjust number so only the specified number of numbers after the decimal point are shown
	tmpNum *= Math.pow(10,decimalNum);
	tmpNum = Math.round(Math.abs(tmpNum))
	tmpNum /= Math.pow(10,decimalNum);
	tmpNum *= iSign;					     // Readjust for sign
	
	// Add digit value
	tmpNum = tmpNum.toFixed(trailDecimal);
	
	// Create a string object to do our formatting on
	var tmpNumStr = new String(tmpNum);
  
	// See if we need to strip out the leading zero or not.
	if (!bolLeadingZero && num < 1 && num > -1 && num != 0)
		if (num > 0) {
		  tmpNumStr = tmpNumStr.substring(1,tmpNumStr.length);
		} else {
			  tmpNumStr = "-" + tmpNumStr.substring(2,tmpNumStr.length);
		  }
	
	// See if we need to put in the commas
	if (bolCommas && (num >= 1000 || num <= -1000)) {
		var iStart = tmpNumStr.indexOf(".");
		if (iStart < 0) { iStart = tmpNumStr.length; }

		iStart -= 3;
		while (iStart >= 1) {
			tmpNumStr = tmpNumStr.substring(0,iStart) + "," + tmpNumStr.substring(iStart,tmpNumStr.length);
			iStart -= 3;
		}
	}

	// See if we need to use parenthesis
	if (bolParens && num < 0) {
		tmpNumStr = "(" + tmpNumStr.substring(1,tmpNumStr.length) + ")";
	}
  
  // Add prefix
  if(prefix.length > 0) { tmpNumStr = prefix + tmpNumStr; }
  
	return tmpNumStr;
}
/*
EXAMPLE :
  var value = 123;
  var valueFormated = FormatNumber(value, 2, true, true, true, 2, "$ "); // output "$ 123.00"
  var value = -123;
  var valueFormated = FormatNumber(value, 2, true, true, true, 2, "$ "); // output "$ (123.00)"
*/

function UnformatNumber(num) {
  var iSign = num.indexOf("(") != -1 ? -1 : 1;
  var reg = new RegExp("[\\$]|[ ]|[,]|[(]|[)]" , "gi");
  var number = num.replace(reg, "");
  var trailDecimal = number.indexOf(".") != -1 ? number.substring(number.indexOf(".") + 1, number.length).length : 0;
  
  number = Number(number * iSign);
  number = number.toFixed(trailDecimal);
  
  if(number != 0) {
    return number;
  } else {
      return "";
    }
}
/*
EXAMPLE :
  var value = "$ 123.00";
  var valueUnFormated = UnformatNumber(value); // output "123.00"
  var value = "$ (123.00)";
  var valueUnFormated = UnformatNumber(value); // output "-123.00"
*/

function DownloadScriptFile(path) {
  var oScript = document.createElement("script");
  oScript.src = path;
  document.body.appendChild(oScript);
}

//////////////////////////////////////////////////////////////
//                        HOT KEYS                          //
//////////////////////////////////////////////////////////////
function HotKeys() {
  // Monitor the control + s (if trigger, save data and cancel update)
  var keystroke = String.fromCharCode(event.keyCode).toLowerCase();
  
  // Control + S (keyboard shortcut for saving data)
  if(event.ctrlKey && keystroke == "s") {
    // Your code ... SaveToServer(1);
  }
  
  // Control + N (keyboard shortcut for new element)
  if(event.ctrlKey && keystroke == "n") {
    // Your code ... SaveToServer(0);
    // Your code ... AppendNewEntry();
  }
}

//////////////////////////////////////////////////////////////
//      COOKIE (GET, SET, DELETE) (by Patrick Hunlock)      //
//////////////////////////////////////////////////////////////
function GetCookie(name) {
  var start = document.cookie.indexOf( name + "=" );
  var len = start + name.length + 1;
  
  if((!start) && (name != document.cookie.substring(0, name.length))) {
    return null;
  }
  if(start == -1) return null;
  var end = document.cookie.indexOf( ";", len );
  if(end == -1) end = document.cookie.length;
  
  return unescape(document.cookie.substring(len, end));
}

function SetCookie(name, value, expires, path, domain, secure) {
  var today = new Date();
  
  today.setTime(today.getTime());
  if(expires) {
    expires = expires * 1000 * 60 * 60 * 24;
  }
  
  var expires_date = new Date( today.getTime() + (expires));
  document.cookie = name+'='+escape( value ) +
    ((expires) ? ';expires='+expires_date.toGMTString() : '') + //expires.toGMTString()
    ((path) ? ';path=' + path : '') +
    ((domain) ? ';domain=' + domain : '') +
    ((secure) ? ';secure' : '');
}

function DeleteCookie(name, path, domain) {
  if (getCookie(name)) document.cookie = name + '=' +
      ((path) ? ';path=' + path : '') +
      ((domain) ? ';domain=' + domain : '' ) +
      ';expires=Thu, 01-Jan-1970 00:00:01 GMT';
}

//////////////////////////////////////////////////////////////
//   ALLOWS/PREVENTS USER FROM SELECTING TEXT ON THE PAGE   //
//////////////////////////////////////////////////////////////
function BlockSelection(prevent) {
	if(typeof prevent != "undefined" && prevent === false) {
		if(typeof document.onselectstart != "undefined") {
			document.onselectstart = null;
		} else {
			  document.onmousedown = null;
			  document.onmouseup = null;
		  }
	} else {
		  if(typeof document.onselectstart != "undefined") {
			  document.onselectstart = DisableSelect;
		  } else {
			  document.onmousedown = DisableSelect;
			  document.onmouseup = function(){ return true; };
		  }
	  }
}

function DisableSelect(evt){
  try {
	  var oEle = (typeof evt == "undefined" || typeof evt.target == "undefined") ? window.event.srcElement : evt.target;
	  if (typeof oEle.tagName != "undefined") {
		  return false;
	  } else {
		    return true;
	    }
	  
  } catch(e) {
      StatusBarWrite("Error (fnc : " + "DisableSelect" + "). " + e.message, 3000);
  }
}
/*
EXAMPLE :
  var oEle = document.getElementById("id");
  oEle.setAttribute("onmouseover", "BlockSelection(true);");
  oEle.setAttribute("onmouseout", "BlockSelection(false);");
*/

//////////////////////////////////////////////////////////////
//                KEYBOARD KEY PRESS RETURN                 //
//////////////////////////////////////////////////////////////
function GetKeyEnter(k) {
	// This function return a string for the US keyboard setting
	// You can change those value for other language validation
	var entry = "";
	
  switch(k) {
  	// Number
		case 48 :
			entry = "0";
			break;
		case 49 :
			entry = "1";
			break;
		case 50 :
			entry = "2";
			break;
		case 51 :
			entry = "3";
			break;
		case 52 :
			entry = "4";
			break;
		case 53 :
			entry = "5";
			break;
		case 54 :
			entry = "6";
			break;
		case 55 :
			entry = "7";
			break;
		case 56 :
			entry = "8";
			break;
		case 57 :
			entry = "9";
			break;
		
  	// Letter
		case 65 :
			entry = "a";
			break;
		case 66 :
			entry = "b";
			break;
		case 67 :
			entry = "c";
			break;
		case 68 :
			entry = "d";
			break;
		case 69 :
			entry = "e";
			break;
		case 70 :
			entry = "f";
			break;
		case 71 :
			entry = "g";
			break;
		case 72 :
			entry = "h";
			break;
		case 73 :
			entry = "i";
			break;
		case 74 :
			entry = "j";
			break;
		case 75 :
			entry = "k";
			break;
		case 76 :
			entry = "l";
			break;
		case 77 :
			entry = "m";
			break;
		case 78 :
			entry = "n";
			break;
		case 79 :
			entry = "o";
			break;
		case 80 :
			entry = "p";
			break;
		case 81 :
			entry = "q";
			break;
		case 82 :
			entry = "r";
			break;
		case 83 :
			entry = "s";
			break;
		case 84 :
			entry = "t";
			break;
		case 85 :
			entry = "u";
			break;
		case 86 :
			entry = "v";
			break;
		case 87 :
			entry = "w";
			break;
		case 88 :
			entry = "x";
			break;
		case 89 :
			entry = "y";
			break;
		case 90 :
			entry = "z";
			break;
  	
		// Other
    case 8 :
      entry = "backspace";
      break;
    case 9 :
      entry = "tab";
      break;
    case 13 :
      entry = "enter";
      break;
    case 16 :
      entry = "shift";
      break;
    case 17 :
      entry = "ctrl";
      break;
    case 18 :
      entry = "alt";
      break;
    case 19 :
      entry = "pause-break";
      break;
    case 20 :
      entry = "caps-lock";
      break;
    case 27 :
      entry = "escape";
      break;
    case 33 :
      entry = "page-up";
      break;
    case 34 :
      entry = "page-down";
      break;
    case 35 :
      entry = "end";
      break;
    case 36 :
      entry = "home";
      break;
    case 37 :
      entry = "left-arrow";
      break;
    case 38 :
      entry = "up-arrow";
      break;
    case 39 :
      entry = "right-arrow";
      break;
    case 40 :
      entry = "down-arrow";
      break;
    case 45 :
      entry = "insert";
      break;
    case 46 :
      entry = "delete";
      break;
    case 91 :
      entry = "left-window-key";
      break;
    case 92 :
      entry = "right-window-key";
      break;
    case 93 :
      entry = "select-key";
      break;
    case 96 :
      entry = "0"; // numeric keyboard
      break;
    case 97 :
      entry = "1"; // numeric keyboard
      break;
    case 98 :
      entry = "2"; // numeric keyboard
      break;
    case 99 :
      entry = "3"; // numeric keyboard
      break;
    case 100 :
      entry = "4"; // numeric keyboard
      break;
    case 101 :
      entry = "5"; // numeric keyboard
      break;
    case 102 :
      entry = "6"; // numeric keyboard
      break;
    case 103 :
      entry = "7"; // numeric keyboard
      break;
    case 104 :
      entry = "8"; // numeric keyboard
      break;
    case 105 :
      entry = "9"; // numeric keyboard
      break;
    case 106 :
      entry = "*"; // numeric keyboard multiply
      break;
    case 107 :
      entry = "+"; // numeric keyboard add
      break;
    case 109 :
      entry = "-"; // numeric keyboard subtract
      break;
    case 110 :
      entry = "."; // numeric keyboard decimal point
      break;
    case 111 :
      entry = "/"; // numeric keyboard divide
      break;
    case 112 :
      entry = "f1";
      break;
    case 113 :
      entry = "f2";
      break;
    case 114 :
      entry = "f3";
      break;
    case 115 :
      entry = "f4";
      break;
    case 116 :
      entry = "f5";
      break;
    case 117 :
      entry = "f6";
      break;
    case 118 :
      entry = "f7";
      break;
    case 119 :
      entry = "f8";
      break;
    case 120 :
      entry = "f9";
      break;
    case 121 :
      entry = "f10";
      break;
    case 122 :
      entry = "f11";
      break;
    case 123 :
      entry = "f12";
      break;
    case 144 :
      entry = "num-lock";
      break;
    case 145 :
      entry = "scroll-lock";
      break;
    case 186 :
      entry = ";";
      break;
    case 187 :
      entry = "=";
      break;
    case 188 :
      entry = ",";
      break;
    case 189 :
      entry = "-";
      break;
    case 190 :
      entry = ".";
      break;
    case 191 :
      entry = "/";
      break;
    case 192 :
      entry = "`"; // grave accent (beside the key 1 on your key board)
      break;
    case 219 :
      entry = "[";
      break;
    case 220 :
      entry = "\\"; // back slash
      break;
    case 221 :
      entry = "]";
      break;
    case 222 :
      entry = "'"; // single quote
      break;
	}
	
	return entry;
}
/*
EXAMPLE :
  var k = (browser.isIE) ? window.event.keyCode : evt.keyCode; // String.fromCharCode(k).toLowerCase()
  var character = GetKeyEnter(k);
*/
