var g_cdata_start = "<![CDATA[";
var g_cdata_end   = "]]>";


// numeric sorting
function numOrdA(a, b){ return (a-b); }
function numOrdD(a, b){ return (b-a); }

function set_options_for_select(the_select, opt_data) {
   while (the_select.options.length) {
      the_select.remove(the_select.options.length - 1);
   }

   for (var i = 0; i < opt_data.length; i++) {
      var option = document.createElement('OPTION');
      option.text  = opt_data[i].text;
      option.value = opt_data[i].value;
      the_select.options[the_select.options.length] = option;
   }
}

function arrayIndexOf(arr, obj, fromIndex) {
    if (fromIndex == null) {
        fromIndex = 0;
    } else if (fromIndex < 0) {
        fromIndex = Math.max(0, arr.length + fromIndex);
    }
    for (var i = fromIndex, j = arr.length; i < j; i++) {
        if (arr[i] === obj)
            return i;
    }
    return -1;
}

var mouse_move_is_IE = null;
function getMouseXY(e) {
   if (mouse_move_is_IE === null) 
   {  mouse_move_is_IE = true;
      var IE = document.all?true:false;
      if (!IE) document.captureEvents(Event.MOUSEMOVE)
   }
   else
   {  mouse_move_is_IE = false;
   }
   var tempX = 0;
   var tempY = 0;

   if (IE) { // grab the x-y pos.s if browser is IE
   tempX = event.clientX + document.body.scrollLeft;
   tempY = event.clientY + document.body.scrollTop;
   }
   else {  // grab the x-y pos.s if browser is NS
   tempX = e.pageX;
   tempY = e.pageY;
   }  
   if (tempX < 0){tempX = 0;}
   if (tempY < 0){tempY = 0;}  
   var coord = new Object();
   coord.x = tempX;
   coord.y = tempY;
   return coord;
}

// thanks quirksmode!
function findPos(obj, stop_el)
{
   var curleft = curtop = 0;

   
   if (obj.offsetParent) {
//Every time we find a new object, we add its offsetLeft and offsetTop to curleft and curtop.

   do {
      if (obj == stop_el) break;
         curleft += obj.offsetLeft;
         curtop += obj.offsetTop;

//The tricky bit: return value of the = operator
////Now we get to the tricky bit:

      } while (obj = obj.offsetParent)
   }
      return [curleft,curtop];
}

function getOffset( el ) {
    var _x = 0;
    var _y = 0;
    while( el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
        _x += el.offsetLeft - el.scrollLeft;
        _y += el.offsetTop - el.scrollTop;
        el = el.offsetParent;
    }
    return { top: _y, left: _x };
}

function stopBubble(ev) 
{
   if (typeof ev.stopPropagation != 'undefined')
   {  ev.stopPropagation();
   }
   if (typeof ev.cancelBubble != 'undefined')
   {  ev.cancelBubble = true;
   }
}

function abbrev_text(t, char_limit)
{  t = trim(escape_js_text(t));
   if (t == "")
   {  return "(blank)"; 
   }

   var t_out = "";

   // overkill, but take as many words as the number of characters
   //  divided by 2 plus one extra for worst case
   var words = t.split(' ', 1 + char_limit/2);
   var complete = true;
  
   // did we still have more words left over?
   if (words.length > char_limit / 2)
   {  complete = false;
   }
    
   var i;

   for (i = 0; i < words.length; i++)
   {  
      if (t_out.length + words[i].length + 1 > char_limit)
      {  break;
      }
      if (t_out)
      {  t_out += " ";
      }
      t_out += words[i];
   }

   if (i < words.length)
   {  complete = false;
   }

   if (!complete && t_out.length < char_limit / 2)
   {  t_out += words[i].substring(0, char_limit - t_out.length);
   }


   if (!complete)
   {  t_out += "...";
   }

   return t_out;
}

function render_text(t)
{
   t = escape_js_text(t);

   var str = t.replace(/\r/g,'');
   var lines = str.split('\n');
   var line_count = lines.length;

   var retval = new Object();

   retval.needs_more_link = line_count > 5;
   retval.long_version  = do_render_text(t);
   retval.short_version = do_render_text(t, 5);
   return retval;
}

function do_render_text(t, max_lines)
{  

   var str = t.replace(/\r/g,'');
   var lines = str.split('\n');
   var line_count = lines.length;
   if (max_lines)
   {  line_count = max_lines < line_count ? max_lines : line_count;
   }

   var STATE_NONE   = 0;
   var STATE_BULLET = 1;
   var STATE_TABLE  = 2;
   var state = STATE_NONE;

   var out = "";
   var last_depth = 0;

   for (var i = 0; i < line_count; i++) {

      var line = lines[i];
   // bold

      line = line.replace(/(^|[\s\(])\*([^\s]+?|[^\s].*?[^\s])\*($|[\s\,\.\;\:\!\?\)])/g, 
         '$1<B>$2</B>$3');

   // italic 
      line = line.replace(/(^|[\s\(])_([^\s]+?|[^\s].*?[^\s])_($|[\s\,\.\;\:\!\?\)])/g, 
         '$1<I>$2</I>$3');

   // strikethrough
      line = line.replace(/(^|[\s\(])-([^\s]+?|[^\s].*?[^\s])-($|[\s\,\.\;\:\!\?\)])/g, 
         '$1<DEL>$2</DEL>$3');

   // bold code
      line = line.replace(/(^|[\s\(])==([^\s]+?|[^\s].*?[^\s])==($|[\s\,\.\;\:\!\?\)])/g, 
         '$1<B><CODE>$2</CODE></B>$3');

   // code 
      line = line.replace(/(^|[\s\(])=([^\s]+?|[^\s].*?[^\s])=($|[\s\,\.\;\:\!\?\)])/g, 
         '$1<CODE>$2</CODE>$3');


      var match= line.match(/(^([\s]+)\*[\s])(.*)/);
      if (match) {
         if (state == STATE_TABLE) {
            out += "</TABLE>";
            out += "<UL>";
         } else if (state == STATE_BULLET) {
            var depth = match[2].length;
            if (depth > last_depth) {
               for (var j = 0; j < depth - last_depth; j++) {
                  out += "<UL>";
               }
            } else if (depth < last_depth) {
               for (var j = 0; j < last_depth - depth; j++) {
                  out += "</UL>";
               }
            }
         } else if (state == STATE_NONE) {
            var depth = match[2].length;
            if (depth > last_depth) {
               for (var j = 0; j < depth - last_depth; j++) {
                  out += "<UL>";
               }
            }
            // start indent
         }
         out += "<LI>" + match[3];
         state = STATE_BULLET;
         last_depth = depth;
         continue;
      } 

      // a table has 0 or more spaces, then at least 1 |, then whatever, 
      //  then another |, then 0 or more spaces
      match= line.match(/^([\s]*)(\|.*\|)([\s]*)$/);
      if (match) {
         if (state == STATE_TABLE) {
            // nothing
         } else if (state == STATE_BULLET) {
            // close out
            for (var j = 0; j < last_depth; j++) {
               out += "</UL>";
            }
            last_depth = 0;
            out += "<TABLE BORDER class='auto_table'>";
         } else if (state == STATE_NONE) {
            out += "<TABLE BORDER class='auto_table'>";
         } 
         var fields = line.split('|');
         out += "<TR>";
         for (var j = 0; j < fields.length; j++) {
            if (!trim(fields[j])) continue;
            out += "<TD>" + fields[j] + "</TD>";
         }
         out += "</TR>";
         state = STATE_TABLE;
         continue;
      }
      else {
         if (state == STATE_TABLE) {
            out += "</TABLE>";
         } else if (state == STATE_BULLET) {
            for (var j = 0; j < last_depth; j++) {
               out += "</UL>";
            }
            last_depth = 0;
         }
         out += line + "<BR>";
         state = STATE_NONE;
      }
   }

   if (state == STATE_TABLE) {
      // close table
   } else if (state == STATE_BULLET) {
      out += "</UL>";
   }

      //'1:$1 2:$2 3:$3 4:$4 5:$5 ');

   out =  out.replace(/(\(?\bhttp:\/\/[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#\/%=~_()|])/g, '<A ONCLICK="stopBubble(event)" HREF="$1" TARGET="_BLANK">$1</A>');
   
   return out;
}

function escape_js_text(t)
{
   t = t.replace(/</g, '&lt;');
   t = t.replace(/>/g, '&gt;');

   // so that people can control spacing
   // todo: should detect >1 space and then do controlled spacing
   //t = t.replace(/ /g, '&thinsp;');
   //t = t.replace(/ /g, '&nbsp;');
   //t = t.replace(/ /g, '&ensp;');

   //t = t.replace(/\(?\bhttp://[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_()|]/g, 'URL');

/*   re = new RegExp(/(\(?\bhttp:\/\/[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#\/%=~_()|])/g);

   re_result = re.exec(t);

   if (re_result)
   {  t = "(LINKY)" + RegExp.$1 + "(/LINKY)";
      dBug(RegExp);
   } */
/*    if (re.exec(ua) != null)
      rv = parseFloat( RegExp.$1 );
   t = t.replace(/\(?\bhttp:\/\/[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#\/%=~_()|]/g, $1+'URL');
t   
*/
// must do last!
//   t = t.replace(/\n/g, '<br>');
   return  t;
}

function remove_all_children_by_id(el_name)
{
   var cell = document.getElementById(el_name);

   if (cell && cell.hasChildNodes())
   {
      while (cell.childNodes.length >= 1)
      {  cell.removeChild(cell.firstChild);
      }
   }
}

function remove_all_children(el)
{
   while (el.childNodes.length >= 1)
   {  el.removeChild(el.firstChild);
   }
}


function get_modifiers(e) {
   if (!e) 
   {  e = window.event;
   }
   mods = new Object();
   mods.ctrl  =0;
   mods.alt   = 0;
   mods.shift = 0;
   mods.meta  = 0;

   if (parseInt(navigator.appVersion)>3) {

      var evt = navigator.appName=="Netscape" ? e:event;

      if (navigator.appName=="Netscape" && parseInt(navigator.appVersion)==4) {
      // NETSCAPE 4 CODE
         var mString =(e.modifiers+32).toString(2).substring(3,6);
         mods.shift = (mString.charAt(0)=="1");
         mods.ctrl  = (mString.charAt(1)=="1");
         mods.alt   = (mString.charAt(2)=="1");
         return mods;
      }
   }

   // NEWER BROWSERS [CROSS-PLATFORM]
   evt = e;
   mods.shift = evt.shiftKey;
   mods.ctrl  = evt.ctrlKey;
   mods.alt   = evt.altKey;
   mods.meta  = evt.metaKey;
  
 return mods;
}
// this function makes sure that any stuff sent withing XML to the
//  server is wrapped in the CDATA business, and also makes sure
//  there are no CDATA endings in the string
function xml_escape(s)
{  s = "" + s; // in case a number
   //s = trim(s); // disabled to allow spaces in payloads
   s = s.replace(g_cdata_end, "]]");
   return g_cdata_start + s + g_cdata_end;
}

var g_start_time = new Date();
var g_last_dBug_time = null;

function time_str(date_item) {
   var amt = date_item.getMinutes()*60*1000 + 
            date_item.getSeconds()*1000 + 
            date_item.getMilliseconds();

   return "" + amt;
}

function dBug(s)
{
   var now = new Date();
   var dur = new Date();
   dur.setTime(now.getTime() - g_start_time.getTime());
   var out = "T_tot: " + time_str(dur) + " ";

   if (g_last_dBug_time) {
      dur.setTime(now.getTime() - g_last_dBug_time.getTime());
      out += "T_delta: " + time_str(dur) + " ";
   } 
   g_last_dBug_time = now;

   if (typeof console != 'undefined' &&
       typeof console.log != 'undefined')
   {  console.log(out + ": " + s);
   }
}

function trim(s) {
   s += "";
   var l=0; var r=s.length -1;
   while(l < s.length && s[l] == ' ')
   {  l++; }
   while(r > l && s[r] == ' ')
   {  r-=1; }
   return s.substring(l, r+1);
}

function clone(myObj)
{
   if(typeof(myObj) != 'object') return myObj;
   if(myObj == null) return myObj;

   var myNewObj = new Object();

   for(var i in myObj)
      myNewObj[i] = clone(myObj[i]);

   return myNewObj;
}

function delete_cookie ( cookie_name )
{
  var cookie_date = new Date ( );  // current date & time
  cookie_date.setTime ( cookie_date.getTime() - 1 );
  document.cookie = cookie_name += "=; expires=" + cookie_date.toGMTString();
}

function urlencode( str ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      input by: AJ
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Brett Zamir (http://brettz9.blogspot.com)
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +      input by: travc
    // +      input by: Brett Zamir (http://brettz9.blogspot.com)
    // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Lars Fischer
    // %          note 1: info on what encoding functions to use from: http://xkr.us/articles/javascript/encode-compare/
    // *     example 1: urlencode('Kevin van Zonneveld!');
    // *     returns 1: 'Kevin+van+Zonneveld%21'
    // *     example 2: urlencode('http://kevin.vanzonneveld.net/');
    // *     returns 2: 'http%3A%2F%2Fkevin.vanzonneveld.net%2F'
    // *     example 3: urlencode('http://www.google.nl/search?q=php.js&ie=utf-8&oe=utf-8&aq=t&rls=com.ubuntu:en-US:unofficial&client=firefox-a');
    // *     returns 3: 'http%3A%2F%2Fwww.google.nl%2Fsearch%3Fq%3Dphp.js%26ie%3Dutf-8%26oe%3Dutf-8%26aq%3Dt%26rls%3Dcom.ubuntu%3Aen-US%3Aunofficial%26client%3Dfirefox-a'
                             
    var histogram = {}, tmp_arr = [];
    var ret = (str+'').toString();
    
    var replacer = function(search, replace, str) {
        var tmp_arr = [];
        tmp_arr = str.split(search);
        return tmp_arr.join(replace);
    };
    
    // The histogram is identical to the one in urldecode.
    histogram["'"]   = '%27';
    histogram['(']   = '%28';
    histogram[')']   = '%29';
    histogram['*']   = '%2A';
    histogram['~']   = '%7E';
    histogram['!']   = '%21';
    histogram['%20'] = '+';
    histogram['\u00DC'] = '%DC';
    histogram['\u00FC'] = '%FC';
    histogram['\u00C4'] = '%D4';
    histogram['\u00E4'] = '%E4';
    histogram['\u00D6'] = '%D6';
    histogram['\u00F6'] = '%F6';
    histogram['\u00DF'] = '%DF';
    histogram['\u20AC'] = '%80';
    histogram['\u0081'] = '%81';
    histogram['\u201A'] = '%82';
    histogram['\u0192'] = '%83';
    histogram['\u201E'] = '%84';
    histogram['\u2026'] = '%85';
    histogram['\u2020'] = '%86';
    histogram['\u2021'] = '%87';
    histogram['\u02C6'] = '%88';
    histogram['\u2030'] = '%89';
    histogram['\u0160'] = '%8A';
    histogram['\u2039'] = '%8B';
    histogram['\u0152'] = '%8C';
    histogram['\u008D'] = '%8D';
    histogram['\u017D'] = '%8E';
    histogram['\u008F'] = '%8F';
    histogram['\u0090'] = '%90';
    histogram['\u2018'] = '%91';
    histogram['\u2019'] = '%92';
    histogram['\u201C'] = '%93';
    histogram['\u201D'] = '%94';
    histogram['\u2022'] = '%95';
    histogram['\u2013'] = '%96';
    histogram['\u2014'] = '%97';
    histogram['\u02DC'] = '%98';
    histogram['\u2122'] = '%99';
    histogram['\u0161'] = '%9A';
    histogram['\u203A'] = '%9B';
    histogram['\u0153'] = '%9C';
    histogram['\u009D'] = '%9D';
    histogram['\u017E'] = '%9E';
    histogram['\u0178'] = '%9F';
    
    // Begin with encodeURIComponent, which most resembles PHP's encoding functions
    ret = encodeURIComponent(ret);
    
    for (search in histogram) {
        replace = histogram[search];
        ret = replacer(search, replace, ret) // Custom replace. No regexing
    }
    
    // Uppercase for full PHP compatibility
    return ret.replace(/(\%([a-z0-9]{2}))/g, function(full, m1, m2) {
        return "%"+m2.toUpperCase();
    });
    
    return ret;
}

function getInternetExplorerVersion()
// Returns the version of Internet Explorer or a -1
// (indicating the use of another browser).
{
  var rv = -1; // Return value assumes failure.
  if (navigator.appName == 'Microsoft Internet Explorer')
  {
    var ua = navigator.userAgent;
    var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
    if (re.exec(ua) != null)
      rv = parseFloat( RegExp.$1 );
  }
  return rv;
}

  var keyStr = "ABCDEFGHIJKLMNOP" +
                "QRSTUVWXYZabcdef" +
                "ghijklmnopqrstuv" +
                "wxyz0123456789+/" +
                "=";

function encode64(input) {
   var output = "";
   var chr1, chr2, chr3 = "";
   var enc1, enc2, enc3, enc4 = "";
   var i = 0;

   do {
      chr1 = input.charCodeAt(i++);
      chr2 = input.charCodeAt(i++);
      chr3 = input.charCodeAt(i++);

      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;

      if (isNaN(chr2)) {
         enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
         enc4 = 64;
      }

      output = output +
         keyStr.charAt(enc1) +
         keyStr.charAt(enc2) +
         keyStr.charAt(enc3) +
         keyStr.charAt(enc4);
      chr1 = chr2 = chr3 = "";
      enc1 = enc2 = enc3 = enc4 = "";
   } while (i < input.length);

   return output;
}

function decode64(input) {
   var output = "";
   var chr1, chr2, chr3 = "";
   var enc1, enc2, enc3, enc4 = "";
   var i = 0;

   // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
   var base64test = /[^A-Za-z0-9\+\/\=]/g;
   if (base64test.exec(input)) {
      alert("There were invalid base64 characters in the input text.\n" +
            "Valid base64 characters are A-Z, a-z, 0-9, �+�, �/�, and �=�\n" +
            "Expect errors in decoding.");
   }
   input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");

   do {
// ??? does indexOf work in IE ???
      enc1 = keyStr.indexOf(input.charAt(i++));
      enc2 = keyStr.indexOf(input.charAt(i++));
      enc3 = keyStr.indexOf(input.charAt(i++));
      enc4 = keyStr.indexOf(input.charAt(i++));

      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;

      output = output + String.fromCharCode(chr1);

      if (enc3 != 64) {
         output = output + String.fromCharCode(chr2);
      }
      if (enc4 != 64) {
         output = output + String.fromCharCode(chr3);
      }

      chr1 = chr2 = chr3 = "";
      enc1 = enc2 = enc3 = enc4 = "";

   } while (i < input.length);

   return output;
}











