﻿//Javascript ToolBox
// CONTENTS:
// $ = document.getElementById("a"[, 'b', obj1, obj2])
// Browser detection
// Array.find: returns array of postions the find element exists within source Array
// Array.indexOf: returns position of element within an array
// Array: forEach: Calls a function for each element in the array.
// Array: sizeOf(): returns count of properties (associative indexes) in array object.
// getDocHeight: returns document height (x-browser)
// addslashes, stripslashes
// MousePosn: returns [X,Y] mouse coordinates
// BindArgsToFunction(functionName, arg1, arg2,... argN)
// formatNumber: add commas and leading symbol (e.g., $)
// unformatNumber: remove commas and leading symbol (e.g., $)
// trim, ltrim, rtrim
// Drag and Drop
// ajaxObject: create Ajax 
// serialize, unserialize
// changeOpacity: reduce or increase item's opacity on the fly (object, opacity)
// propagateEventHandler(currentElement, eventName, eventHandlerFunctionToBeCalled)
// animateDiv(divID, transitionEffect[str], transitionSecs[num] )
// setSelRange: Set selection range for input elements (e.g., textarea) [ f(elemID, startPosn, endPosn) ]
// utf8_encode
// htmlspecialchars (string, quote_style)
// get_html_translation_table (used by htmlspecialchars)
// md5 (hash) [grayed out as of 19-Jun-09]

////////////////////////////////////////
// GLOBAL VARIABLES:
var winW = document.body ? document.body.offsetWidth : 0;  //window width
var winH = document.body ? getDocHeight() : 0 ;  //window height
var mouseXposn = 0;  //mouse X position
var mouseYposn = 0;  //mouse Y position
document.onmousemove = MousePosn;  //load the event listener
////////////////////////////////////////
// USEFUL VARIABLES
//	var callerFunc = arguments.callee.caller.toString();
//	var callerFuncName = (callerFunc.substring(callerFunc.indexOf("function") + 8, callerFunc.indexOf("(")) || "anoynmous")

// $$ function = document.getElementById( "a"[, 'b', obj1, obj2] )
function $$() {
	var elements = new Array();
	for (var i = 0; i < arguments.length; i++) {
		var element = arguments[i];
		if (typeof element == 'string')
			element = document.getElementById(element);
		if (arguments.length == 1)
			return element;
		elements.push(element);
	}
	return elements;
}

// GLOBAL VARIABLES for sortTable
var col = 0;
var parent = null;
var items = new Array();
var N = 0;

function get(i) {
	var node = items[i].getElementsByTagName("TD")[col];    
	if(node.childNodes.length == 0) return "";
	var retval = node.firstChild.nodeValue;
	if(parseInt(retval) == retval) return parseInt(retval);
	return retval;
}

function compare(val1, val2, desc) {
	return (desc) ? val1 > val2 : val1 < val2;
}

function exchange(i, j) {
	if(i == j+1) {
	  parent.insertBefore(items[i], items[j]);
	} else if(j == i+1) {
	  parent.insertBefore(items[j], items[i]);
	} else {
	  var tmpNode = parent.replaceChild(items[i], items[j]);
	  if(typeof(items[i]) == "undefined") {
	    parent.appendChild(tmpNode);
	  } else {
	    parent.insertBefore(tmpNode, items[i]);
	  }
	}
}

function quicksort(m, n, desc) {
	if(n <= m+1) return;
	
	if((n - m) == 2) {
	  if(compare(get(n-1), get(m), desc)) exchange(n-1, m);
	  return;
	}
	
	i = m + 1;
	j = n - 1;
	
	if(compare(get(m), get(i), desc)) exchange(i, m);
	if(compare(get(j), get(m), desc)) exchange(m, j);
	if(compare(get(m), get(i), desc)) exchange(i, m);
	
	pivot = get(m);
	
	while(true) {
	  j--;
	  while(compare(pivot, get(j), desc)) j--;
	  i++;
	  while(compare(get(i), pivot, desc)) i++;
	  if(j <= i) break;
	  exchange(i, j);
	}
	
	exchange(m, j);
	
	if((j-m) < (n-j)) {
	  quicksort(m, j, desc);
	  quicksort(j+1, n, desc);
	} else {
	  quicksort(j+1, n, desc);
	  quicksort(m, j, desc);
	}
}

//  sortTable sorts tableID on sortColumn, with desc set true or false for sort order
function sortTable(tableid, n, desc) {
	parent = document.getElementById(tableid);
	col = n;
	
	if(parent.nodeName != "TBODY")
	  parent = parent.getElementsByTagName("TBODY")[0];
	if(parent.nodeName != "TBODY")
	  return false;
	
	items = parent.getElementsByTagName("TR");
	N = items.length;
	
	// quick sort
	quicksort(0, N, desc);
}

/*
// GLOBALS for sortTable
var sortColumn = 0;
var sortTable = null;
var sortTableRows = new Array();
var sortTableRowCount = 0;

function get(i) {
	var node = sortTableRows[i].getElementsByTagName("TD")[sortColumn];    
	if(node.childNodes.length == 0) return "";
	var retval = node.firstChild.nodeValue;
	if(parseInt(retval) == retval) return parseInt(retval);
	return retval;
}

function compare(val1, val2, desc) {
	return (desc) ? val1 > val2 : val1 < val2;
}

function exchange(i, j) {
	if(i == j+1) {
		sortTable.insertBefore(sortTableRows[i], sortTableRows[j]);
		} else if(j == i+1) {
			sortTable.insertBefore(sortTableRows[j], sortTableRows[i]);
		} else {
			var tmpNode = sortTable.replaceChild(sortTableRows[i], sortTableRows[j]);
			if(typeof(sortTableRows[i]) == "undefined") {
			sortTable.appendChild(tmpNode);
		} else {
			sortTable.insertBefore(tmpNode, sortTableRows[i]);
		}
	}
}

function quickSort(sortStart, sortEnd, desc) {
	if(sortEnd <= sortStart+1) return;
	
	if((sortEnd - sortStart) == 2) {
	  if(compare(get(sortEnd-1), get(sortStart), desc)) exchange(sortEnd-1, sortStart);
	  return;
	}
	
	lowEnd = sortStart + 1;
	highEnd = sortEnd - 1;
	
	if(compare(get(sortStart), get(lowEnd), desc)) exchange(lowEnd, sortStart);
	if(compare(get(highEnd), get(sortStart), desc)) exchange(sortStart, highEnd);
	if(compare(get(sortStart), get(lowEnd), desc)) exchange(lowEnd, sortStart);
	
	pivot = get(sortStart);
	
	while(true) {
	  highEnd--;
	  while(compare(pivot, get(highEnd), desc)) highEnd--;
	  lowEnd++;
	  while(compare(get(lowEnd), pivot, desc)) lowEnd++;
	  if(highEnd <= lowEnd) break;
	  exchange(lowEnd, highEnd);
	}
	
	exchange(sortStart, highEnd);
	
	if((highEnd-sortStart) < (sortEnd-highEnd)) {
	  quickSort(sortStart, highEnd, desc);
	  quickSort(highEnd+1, sortEnd, desc);
	} else {
	  quickSort(highEnd+1, sortEnd, desc);
	  quickSort(sortStart, highEnd, desc);
	}
}

//  sortTable sorts tableID on sortCol, with desc set false for ascending or true for descending sort order
function sortTable(tableID, sortCol, desc) {
	sortTable = $(tableID);
	sortColumn = sortCol;
	if(sortTable.nodeName != "TBODY")
		sortTable = sortTable.getElementsByTagName("TBODY")[0];
	if(sortTable.nodeName != "TBODY")
		return false;
	
	sortTableRows = sortTable.getElementsByTagName("TR");
	sortTableRowCount = sortTableRows.length;
	
	// quick sort
	quickSort(0, sortTableRowCount, desc);
}
*/

//Detect Vista (from http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_22112199.html)
function isVista() {
	return (navigator.userAgent.indexOf('Windows NT 6.0') != -1);  
}

//Detect FireFox; returns true/false
function isFireFox() {
	var FFversion = 0;
	if (/Firefox[\/\s](\d+\.\d+)/.test(navigator.userAgent)) { //test for Firefox/x.x or Firefox x.x (ignoring remaining digits);
		FFversion = new Number(RegExp.$1) // capture x.x portion and store as a number
	}
	return FFversion;
}
//Detect IE; returns true/false
function isIE() {
	var IEversion = 0;
	if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)){ //test for MSIE x.x;
		IEversion=new Number(RegExp.$1) // capture x.x portion and store as a number
	}
	return IEversion;
}

// Array Search
// returns false or array of indexes identifying the found positions in the array
// usage: var thirty = arrayToSearch.find(30); 
Array.prototype.find = function(searchItem, inExactSearch) {
	var returnArray = false;
	for (i=0; i<this.length; i++) {  //FOR [search array]
		if (typeof(searchItem) == 'function') {  //IF [array item == FUNCTION]
			if (searchItem.test(this[i])) {
				if (!returnArray) { returnArray = []; }
					returnArray.push(i);
				}
			} else {  //ELSEIF [array item == non function]
				if (!arguments[1]) {  //IF [Exact search == YES]
					if (this[i]===searchItem) {
						if (!returnArray) { returnArray = []; }
							returnArray.push(i);
						}
			} else {  //ELSEIF [Exact search == NO]
				if (this[i]==searchItem) {
					if (!returnArray) { returnArray = []; }
						returnArray.push(i);
					}
			}  //ENDIF [Exact search]
		}
	}  //ENDFOR [search array]
return returnArray;
}

if (!Array.prototype.indexOf) {  //IF [indexOf not yet defined]
  Array.prototype.indexOf = function(elt /*, from*/) {
    var len = this.length >>> 0;

    var from = Number(arguments[1]) || 0;
    from = (from < 0) ? Math.ceil(from) : Math.floor(from);
    if (from < 0) { from += len; }

    for (; from < len; from++) {
      if (from in this && this[from] === elt)
        return from;
    }  //ENDFOR
    return -1;
  };  //ENDFUNCTION
}  //ENDIF [indexOf not yet defined]

// ARRAY forEach 
/*
Description: Calls a function for each element in the array.
Syntax: array.forEach(callback[, thisObject]);

Detail of parameters:
* callback : Function to test each element of the array.
* thisObject : Object to use as this when executing callback.

Return Value:
Returns created array.
*/
if (!Array.prototype.forEach) {  //IF [forEach not defined]
  Array.prototype.forEach = function(fun /*, thisp*/) {
    var len = this.length;
    if (typeof fun != "function") { throw new TypeError(); }

    var thisp = arguments[1];
    for (var i = 0; i < len; i++) {
      if (i in this)
        fun.call(thisp, this[i], i, this);
    }  //ENDFOR
  };  //ENDFUNCTION [forEach]
}  //ENDIF [forEach not defined]

// ARRAY sizeOf 
/*
Description: returns count of properties (associative indexes) in array object 
Syntax: array.sizeOf();

Return Value: Count of items in array object.
*/
if (!Array.prototype.sizeOf) {  //IF [sizeOf not defined]
	Array.prototype.sizeOf = function () {
		var len = this.length ? --this.length : -1;
		for (var item in this) {
			len++;
		}
		return len;
	}  //ENDFUNCTION [sizeOf]
}  //ENDIF [sizeOf not defined]

// x-browser document height
function getDocHeight() {
    var D = document;
    return Math.max(
        Math.max(D.body.scrollHeight, D.documentElement.scrollHeight),
        Math.max(D.body.offsetHeight, D.documentElement.offsetHeight),
        Math.max(D.body.clientHeight, D.documentElement.clientHeight)
    );
}

function addslashes( str ) { 
    return (str+'').replace(/([\\"'])/g, "\\$1").replace(/\0/g, "\\0");
}

function stripslashes( str ) {
    return (str+'').replace(/\0/g, '0').replace(/\\([\\'"])/g, '$1');
}

// x-browser function to retrieve mouse x-y pos
// returns array of [X,Y]
function MousePosn(e) {
	if (isIE()) { // grab the x-y positions if browser is IE
		mouseXposn = event.clientX + document.body.scrollLeft;
		mouseYposn = event.clientY + document.body.scrollTop;
		winW = document.body.offsetWidth;  //get up to date measurement

	} else {  // grab the x-y positions if browser is NS
		mouseXposn = e.pageX;
		mouseYposn = e.pageY;
		winW = window.innerWidth;
	}
	winH=getDocHeight();  //get up to date measurement
  // catch possible negative values in NS4
	mouseXposn = (mouseXposn < 0) ? 0 : mouseXposn;
	mouseYposn = (mouseYposn < 0) ? 0 : mouseYposn;
  // show the position values in the form named DisplayForm
  // in the text fields named MouseX and MouseY
	return [mouseXposn,mouseYposn];
}

// Binds current values of args to the function for execution at a future time
function BindArgsToFunction(fn) {
  var args = [];
  for (var n = 1; n < arguments.length; n++)
    args.push(arguments[n]);
  return function() { return fn.apply(this, args); };
}

// stop event propogation to avoid unwanted mouseouts  
// example call1 (in HTML): onmouseout="cancelBubble(event);"
// example call2 (in js): rowX.onmouseout = BindArgsToFunction(cancelBubble, this.event);
function cancelBubble(e) {
	if (!e) var e = window.event;
//if(!e) {alert('e not defined check calling format'); }  //debug
	e.cancelBubble = true;
	if (e.stopPropagation) e.stopPropagation();
}

//Formatting Numbers with commas and prefix
// Returns the formatted string back into a usable number. 
// Inputs: number and optional prefix ('$' for example) 
function formatNumber(num,prefix){
   prefix = prefix || '';
   num += '';
   var splitStr = num.split('.');
   var splitLeft = splitStr[0];
   var splitRight = splitStr.length > 1 ? '.' + splitStr[1] : '';
   var regx = /(\d+)(\d{3})/;
   while (regx.test(splitLeft)) {
      splitLeft = splitLeft.replace(regx, '$1' + ',' + '$2');
   }  //ENDWHILE
   return prefix + splitLeft + splitRight;
}

function unformatNumber(num) {
   return num.replace(/([^0-9\.\-])/g,'')*1;
}

//sortNum sorts an Array in a numerical fashion instead of by string order 
// Usage: sortedArray=Array.sortNum();
Array.prototype.sortNum = function() {
   return this.sort( function (a,b) { return a-b; } );
}

//String trimming functions
// trim trims both left and right sides
// ltrim and rtrim only one side
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,"");
}

/* Drag and Drop
*  Cross browser Drag Handler
*  http://www.webtoolkit.info/
*  Usage: DragHandler.attach(document.getElementById('ID'));
**/
 
var DragHandler = {
	// private property.
	_oElem : null,
 
	// public method. Attach drag handler to an element.
	attach : function(oElem, oElem2, Elem2XOffset, Elem2YOffset) {
		oElem.onmousedown = DragHandler._dragBegin;
 
		// callbacks
		oElem.dragBegin = new Function();
		oElem.drag = new Function();
		oElem.dragEnd = new Function();
		oElem.tagAlong = oElem2;
		oElem.tagAlongXOffset = Elem2XOffset;
		oElem.tagAlongYOffset = Elem2YOffset;
		return oElem;
	},
	
	// public method. Detach drag handler from an element.
	detach : function(oElem) {
		oElem.onmousedown = DragHandler._nothingFunc;
 	},

	// private method. No Op.
	_nothingFunc : function nothingFunc () {},
 
	// private method. Begin drag process.
	_dragBegin : function(e) {
		var oElem = DragHandler._oElem = this;
 
		if (isNaN(parseInt(oElem.style.left))) { oElem.style.left = '0px'; }
		if (isNaN(parseInt(oElem.style.top))) { oElem.style.top = '0px'; }
		var x = parseInt(oElem.style.left);
		var y = parseInt(oElem.style.top);
		e = e ? e : window.event;
		oElem.mouseX = e.clientX;
		oElem.mouseY = e.clientY;
		oElem.dragBegin(oElem, x, y);
		document.onmousemove = DragHandler._drag;
		document.onmouseup = DragHandler._dragEnd;
		return false;
	},
 
	// private method. Drag (move) element.
	_drag : function(e) {
		var oElem = DragHandler._oElem;
		var x = parseInt(oElem.style.left);
		var y = parseInt(oElem.style.top);
		e = e ? e : window.event;
		oElem.style.left = x + (e.clientX - oElem.mouseX) + 'px';
		oElem.style.top = y + (e.clientY - oElem.mouseY) + 'px';
		oElem.mouseX = e.clientX;
		oElem.mouseY = e.clientY;
		oElem.drag(oElem, x, y);
/*
		if ( oElem.tagAlong ) {  //IF [Tag Along Element DOES exist]
			oElem.tagAlong.drag(oElem.tagAlong, x + oElem.tagAlongXOffset, y + oElem.tagAlongYOffset);
		}  //ENDIF [Tag Along Element DOES exist]
*/
		if ( oElem.tagAlong ) {  //IF [Tag Along Element DOES exist]
			oElem.tagAlong.style.left = x + oElem.tagAlongXOffset + 'px';
			oElem.tagAlong.style.top = y + oElem.tagAlongYOffset + 'px';
		}  //ENDIF [Tag Along Element DOES exist]
		return false;
	},
 
	// private method. Stop drag process.
	_dragEnd : function() {
		var oElem = DragHandler._oElem;
		var x = parseInt(oElem.style.left);
		var y = parseInt(oElem.style.top);
		oElem.dragEnd(oElem, x, y);
		document.onmousemove = null;
		document.onmouseup = null;
		DragHandler._oElem = null;
	}
}  //ENDCLASS [DragHandler]

/*
// Determines if an object is an array or not
// Usage: arrayToTest.isArray()
Object.prototype.isArray = function() {
   return this.constructor == Array;
}

// Gets all elements with a given className
// Returns: array of elements with the specified class name, may be restricted to optional tag (e.g., 'p')
// Usage: elements=document.getElementsByClass('fancyStyle');
Object.prototype.getElementsByClass = function (searchClass, tag) {      
   var returnArray = [];
   tag = tag || '*';
   var els = this.getElementsByTagName(tag);
   var pattern = new RegExp('(^|\\s)'+searchClass+'(\\s|$)');
   for (var i = 0; i < els.length; i++) {
      if ( pattern.test(els[i].className) ) {
         returnArray.push(els[i] );
      }  //ENDIF
   }  //ENDFOR
   return returnArray;
}
*/

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;
		}
	}  //END [abort]
	this.update = function(passData, postMethod) {
		if (that.updating) { return false; }
		that.AJAX = null;
		if (window.XMLHttpRequest) {  //IF [browser == FF]
			that.AJAX=new XMLHttpRequest();
		} else {  //ELSEIF [browser == IE]
			that.AJAX=new ActiveXObject("Microsoft.XMLHTTP");
		}  //ENDIF [browser selection]
		if (that.AJAX==null) {  //IF [AJAX not set]
			return false;
		} else {  //ELSEIF [AJAX is set]
			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;
				}
			}  //ENDFUNCTION [onreadystatechange]
			that.updating = new Date();
			if (/post/i.test(postMethod)) {  //IF [type == POST]
				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 {  //ELSEIF [type == GET]
				var uri=urlCall+'?'+passData+'&timestamp='+(that.updating.getTime()); 
				that.AJAX.open("GET", uri, true);                             
				that.AJAX.send(null);
			}
			return true;
		}  //ENDIF [AJAX is set]
	}  //ENDFUNCTION [anon(passData, postMethod)]
	var urlCall = url;
	this.callback = callbackFunction || function () {};
}  //ENDFUNCTION [ajaxObject]

// USAGE EXAMPLES
// Just a stub function we'll tell ajaxObject to call when it's done
// callback functions get responseText, and responseStat respectively
// in their arguments.
/*
function fin(responseTxt,responseStat) {
  alert(responseStat+' - '+responseTxt);
}
// create a new ajaxObject, give it a url it will be calling and
// tell it to call the function "fin" when it receives data back from the server.
var test1 = new ajaxObject('http://someurl.com/server.cgi',fin);
    test1.update();
                
// create a new ajaxObject, give it a url and tell it to call fin when it
// gets data back from the server.  When we initiate the ajax call we'll
// be passing 'id=user4379' to the server.              
var test2 = new ajaxObject('http://someurl.com/program.php',fin);
    test2.update('id=user4379');
                
// create a new ajaxObject but we'll overwrite the callback function inside
// the object to more tightly bind the object with the response hanlder.
var test3 = new ajaxObject('http://someurl.com/prog.py', fin);
    test3.callback = function (responseTxt, responseStat) {
      // we'll do something to process the data here.
      document.getElementById('someDiv').innerHTML=responseTxt;
    }
    test3.update('coolData=47&userId=user49&log=true'); 
                
// create a new ajaxObject and pass the data to the server (in update) as
// a POST method instead of a GET method.
var test4 = new ajaxObject('http://someurl.com/postit.cgi', fin);
    test4.update('coolData=47&userId=user49&log=true','POST');  
*/

function serialize( mixed_value ) {
    //  for PHP-compatibility js objects are translated to arrays
    // *     example 1: serialize(['Kevin', 'van', 'Zonneveld']);
    // *     returns 1: 'a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}'
    // *     example 2: serialize({firstName: 'Kevin', midName: 'van', surName: 'Zonneveld'});
    // *     returns 2: 'a:3:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";s:7:"surName";s:9:"Zonneveld";}'
 
    var _getType = function( inp ) {
        var type = typeof inp, match;
        var key;
        if (type == 'object' && !inp) {
            return 'null';
        }
        if (type == "object") {
            if (!inp.constructor) {
                return 'object';
            }
            var cons = inp.constructor.toString();
            match = cons.match(/(\w+)\(/);
            if (match) {
                cons = match[1].toLowerCase();
            }
            var types = ["boolean", "number", "string", "array"];
            for (key in types) {
                if (cons == types[key]) {
                    type = types[key];
                    break;
                }
            }
        }
        return type;
    };
    var type = _getType(mixed_value);
    var val, ktype = '';
    
    switch (type) {
        case "function": 
            val = ""; 
            break;
        case "undefined":
            val = "N";
            break;
        case "boolean":
            val = "b:" + (mixed_value ? "1" : "0");
            break;
        case "number":
            val = (Math.round(mixed_value) == mixed_value ? "i" : "d") + ":" + mixed_value;
            break;
        case "string":
            val = "s:" + mixed_value.length + ":\"" + mixed_value + "\"";
            break;
        case "array":
        case "object":
            val = "a";
            /*
            if (type == "object") {
                var objname = mixed_value.constructor.toString().match(/(\w+)\(\)/);
                if (objname == undefined) {
                    return;
                }
                objname[1] = serialize(objname[1]);
                val = "O" + objname[1].substring(1, objname[1].length - 1);
            }
            */
            var count = 0;
            var vals = "";
            var okey;
            var key;
            for (key in mixed_value) {
                ktype = _getType(mixed_value[key]);
                if (ktype == "function") { 
                    continue; 
                }
                
                okey = (key.match(/^[0-9]+$/) ? parseInt(key, 10) : key);
                vals += serialize(okey) +
                        serialize(mixed_value[key]);
                count++;
            }
            val += ":" + count + ":{" + vals + "}";
            break;
    }
    if (type != "object" && type != "array") {
      val += ";";
  }
    return val;
}

function unserialize(data){
    // Takes a string representation of variable and recreates it
    // version: 903.3016
    // discuss at: http://phpjs.org/functions/unserialize
    //  for PHP-compatibility js objects are translated to arrays
    // *       example 1: unserialize('a:3:{i:0;s:5:"Kevin";i:1;s:3:"van";i:2;s:9:"Zonneveld";}');
    // *       returns 1: ['Kevin', 'van', 'Zonneveld']
    // *       example 2: unserialize('a:3:{s:9:"firstName";s:5:"Kevin";s:7:"midName";s:3:"van";s:7:"surName";s:9:"Zonneveld";}');
    // *       returns 2: {firstName: 'Kevin', midName: 'van', surName: 'Zonneveld'}
 
    var error = function (type, msg, filename, line){throw new this.window[type](msg, filename, line);};
    var read_until = function (data, offset, stopchr){
        var buf = [];
        var chr = data.slice(offset, offset + 1);
        var i = 2;
        while (chr != stopchr) {
            if ((i+offset) > data.length) {
                error('Error', 'Invalid');
            }
            buf.push(chr);
            chr = data.slice(offset + (i - 1),offset + i);
            i += 1;
        }
        return [buf.length, buf.join('')];
    };
    var read_chrs = function (data, offset, length){
        var buf;
 
        buf = [];
        for(var i = 0;i < length;i++){
            var chr = data.slice(offset + (i - 1),offset + i);
            buf.push(chr);
        }
        return [buf.length, buf.join('')];
    };
    var _unserialize = function (data, offset){
        var readdata;
        var readData;
        var chrs = 0;
        var ccount;
        var stringlength;
        var keyandchrs;
        var keys;
 
        if(!offset) {offset = 0;}
        var dtype = (data.slice(offset, offset + 1)).toLowerCase();
 
        var dataoffset = offset + 2;
        var typeconvert = new Function('x', 'return x');
 
        switch(dtype){
            case 'i':
                typeconvert = function (x) {return parseInt(x, 10);};
                readData = read_until(data, dataoffset, ';');
                chrs = readData[0];
                readdata = readData[1];
                dataoffset += chrs + 1;
            break;
            case 'b':
                typeconvert = function (x) {return parseInt(x, 10) == 1;};
                readData = read_until(data, dataoffset, ';');
                chrs = readData[0];
                readdata = readData[1];
                dataoffset += chrs + 1;
            break;
            case 'd':
                typeconvert = function (x) {return parseFloat(x);};
                readData = read_until(data, dataoffset, ';');
                chrs = readData[0];
                readdata = readData[1];
                dataoffset += chrs + 1;
            break;
            case 'n':
                readdata = null;
            break;
            case 's':
                ccount = read_until(data, dataoffset, ':');
                chrs = ccount[0];
                stringlength = ccount[1];
                dataoffset += chrs + 2;
 
                readData = read_chrs(data, dataoffset+1, parseInt(stringlength, 10));
                chrs = readData[0];
                readdata = readData[1];
                dataoffset += chrs + 2;
                if(chrs != parseInt(stringlength, 10) && chrs != readdata.length){
                    error('SyntaxError', 'String length mismatch');
                }
            break;
            case 'a':
                readdata = {};
 
                keyandchrs = read_until(data, dataoffset, ':');
                chrs = keyandchrs[0];
                keys = keyandchrs[1];
                dataoffset += chrs + 2;
 
                for(var i = 0;i < parseInt(keys, 10);i++){
                    var kprops = _unserialize(data, dataoffset);
                    var kchrs = kprops[1];
                    var key = kprops[2];
                    dataoffset += kchrs;
 
                    var vprops = _unserialize(data, dataoffset);
                    var vchrs = vprops[1];
                    var value = vprops[2];
                    dataoffset += vchrs;
 
                    readdata[key] = value;
                }
 
                dataoffset += 1;
            break;
            default:
                error('SyntaxError', 'Unknown / Unhandled data type(s): ' + dtype);
            break;
        }
        return [dtype, dataoffset - offset, typeconvert(readdata)];
    };
    return _unserialize(data, 0)[2];
}

function changeOpacity(object, opacityValue) {
	var appVersion = parseInt(navigator.appVersion);
	if (navigator.appName.indexOf("Netscape") != -1 && appVersion >= 5) {  //NS5+
		object.style.MozOpacity=opacityValue/100; 
	}
	if (navigator.appName.indexOf("Microsoft") != -1 && appVersion >=4 && appVersion <=7 ) { //IE4-7
		object.style.filter='alpha(opacity='+opacityValue+')';
	}
	if (navigator.appName.indexOf("Microsoft") != -1 && appVersion >=8 ) { //IE8
		object.style.filter="progid:DXImageTransform.Microsoft.Alpha(opacity="+opacityValue+")";
	}
}

function changeOpacityByID(objectID, opacityValue) {
	var object = document.getElementById(objectID);
		var appVersion = parseInt(navigator.appVersion);
	if (navigator.appName.indexOf("Netscape") != -1 && appVersion >= 5) {  //NS5+
		object.style.MozOpacity=opacityValue/100; 
	}
	if (navigator.appName.indexOf("Microsoft") != -1 && appVersion >=4 && appVersion <=7 ) { //IE4-7
		object.style.filter='alpha(opacity='+opacityValue+')';
	}
	if (navigator.appName.indexOf("Microsoft") != -1 && appVersion >=8 ) { //IE8
		object.style.filter="progid:DXImageTransform.Microsoft.Alpha(opacity="+opacityValue+")";
	}
}

// handle event propogation by placing an event handler on each descendant element within the object
// from http://www.permadi.com/tutorial/jsEventBubbling/index2.html
// calling format example: propagateEventHandler(document.getElementById('MyDiv'), "onclick", onClickHandlerExample);
function propagateEventHandler(currentElement, eventName, eventHandlerFunctionToBeCalled) {
	if (currentElement) {  //IF [element exists == YES]
	    var j;
	    var tagName=currentElement.tagName;
	
/*		
// save the original handler (this is for illustration purpose, it is not necessary)
		if (currentElement[eventName]) {
			if (!currentElement.originalEventHandler) {
				currentElement.originalEventHandler=new Object();
				currentElement.originalEventHandler[eventName]=currentElement[eventName];
			}
		}
		if (currentElement.className=="noEventCapture") {
			return;
		}
*/
		
	// This is needed because IE 7 chokes when trying to assign event to certain elements
		try { currentElement[eventName]=eventHandlerFunctionToBeCalled; }
		catch(error){};
			
	    // Traverse the tree and assign the event handler to every descendant
	    var i=0;
	    var currentElementChild=currentElement.childNodes[i];
	    while (currentElementChild) {
			propagateEventHandler(currentElementChild, eventName, eventHandlerFunctionToBeCalled);
			i++;
			currentElementChild=currentElement.childNodes[i];
	    }  //ENDWHILE
	}  //ENDIF [element exists == YES]
}  //ENDFUNCTION

function onClickHandlerExample(mEvent) {
	if (!mEvent) { mEvent=window.event; }
	if (!mEvent) { return; }
	var firingElement=null;
	//alert(mEvent.srcElement.tagName);		
	// Internet Explorer
	if (mEvent.srcElement) {
		firingElement=mEvent.srcElement;  
	} else {
		if (mEvent.target) { // Netscape and Firefox
			firingElement=mEvent.target;    
		}
	}
// DO SOMETHING USEFUL HERE
// console.log('onclick event fired');
/////////////////////////
/*  if (firingElement.originalEventHandler && firingElement.originalEventHandler["onclick"])
	firingElement.originalEventHandler["onclick"]();	*/
	
// If you do not want the event to "bubble," then uncomment thie line below
// mEvent.cancelBubble=true;
// This may be done selectively based on the element that fired the element by checking the 
// className or id
	return true;
}

// animateDiv (divID, transitionEffect[str], transitionSecs[num] )
// requires CycleSlideShow.js 
function animateDiv(divID, transitionEffect, transitionSecs) {
	jQuery.isReady = true;
	$(document).ready(function (divID, transitionEffect, transitionSecs) {
		// fx options: blindX, blindY, blindZ, cover, curtain, curtainY, fade, fadeZoom, growX, growY, 
		// scrollUp, scrollDown, scrollLeft, scrollRight, scrollHorz, scrollVert, 
		// shuffle, slideX, slideY, toss, turnUp, turnDown, turnLeft, turnRight, uncover, wipe, zoom
		var Transitions = new Array('blindZ', 'curtainY', 'shuffle', 'slideX', 'slideY', 'turnUp', 'turnLeft', 'turnRight', 'wipe', 'zoom',
			'fade', 'fadeZoom', 'toss');  //Final 3 don't work on IE so exlude from IE
	//Losers:  'scrollDown', 'scrollUp', 'scrollHorz', 'scrollVert', 'cover', 'curtain', 'scrollLeft', 'scrollRight', 
	//         'blindY', 'blindX', 'growY', 'growX', 'turnDown', 
	//(cont'd) 'custom, cssBefore: {top: 0,left: 0,width: 0,height: 0,zIndex: 1}, animIn: {width: 300, height: 375}, animOut: {top: 375, left: 300, width: 0, height: 0}, cssAfter: {zIndex: 0}' 
	
		var IEVersion = 0;
		if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)){ //test for MSIE x.x;
			IEVersion=new Number(RegExp.$1) // capture x.x portion and store as a number
		}
		if (IEVersion == 0) {
			randomTransition = Transitions[MyRandom(0, Transitions.length-1)];  //FF
		} else {
			randomTransition = Transitions[MyRandom(0, Transitions.length-3-1)];  //IE
		}
	
		if (!transitionEffect) { transitionEffect = randomTransition; }  //assign a transition effect if none specified
		
		cssTop=0; cssLeft=0; cssWidth=305; cssHeight=375;  //FF defaults
	    if( IEVersion == 0 ) {cssTop=0; cssLeft=0; cssWidth=300; cssHeight=375;}
	
	    animInLeft=0; animInTop=0; animOutLeft=0; animOutTop=0;  //IE settings
	    if( IEVersion == 0 ) {animInLeft=20; animInTop=0; animOutLeft=300; animOutTop=400;}  //FF Settings
	
		$('#'+divID).cycle({
		fx: transitionEffect ,
		
		    animIn: {  
		        left: animInLeft, 
		        top: animInTop
		    }, 
		    animOut: {  
		        left: animOutLeft,   
		        top: animOutTop
		    }, 
	
	/*
		   cssBefore: {  
		        top:  cssTop,
		        left: cssLeft, 
		        width: cssWidth, 
		        height: cssHeight,  
		        zIndex: 1  
		    }, //END [cssBefore]
	        cssAfter: {  
		        zIndex: 1
		    }, //END [cssAfter]
	*/
	
			timeout: transitionSecs*1000  //slide time (in milliseconds)
	//		speed: 600,  //time between slides 
	//		delay: -1000  // start slides sooner
		});  //EnD [cycle]
	}); // END [ready for animateDiv]
}  //ENDFUNCTION [animateDiv]

function setSelRange(elemID, selStart, selEnd) {
	if ( !document.getElementById(elemID) ) {  //IF [elemID object exists == NO]
		if ( console ) { console.log("setSelRange: object |"+elemID+"| non-existent! selStart="+ selStart+", selEnd="+selEnd); } //debug
		return;
	}  //ENDIF [elemID object exists == NO]
	elem = document.getElementById(elemID);
	if (elem.setSelectionRange) {   //IF [FF]
		elem.focus(); 
		elem.setSelectionRange(selStart, selEnd); 
		return;
	}  //ENDIF [FF]
	if (elem.createTextRange) {  //IF [IE]
		var range = elem.createTextRange(); 
		range.collapse(true); 
		range.moveEnd('character', selEnd); 
		range.moveStart('character', selStart); 
		range.select(); 
	}  //ENDIF [IE]
}  //ENDFUNCTION [setSelRange]

function utf8_encode( argString ) {
    // http://kevin.vanzonneveld.net
    // *     example 1: utf8_encode('Kevin van Zonneveld');
    // *     returns 1: 'Kevin van Zonneveld'
 
    var string = (argString+'').replace(/\r\n/g, "\n").replace(/\r/g, "\n");
 
    var utftext = "";
    var start, end;
    var stringl = 0;
 
    start = end = 0;
    stringl = string.length;
    for (var n = 0; n < stringl; n++) {
        var c1 = string.charCodeAt(n);
        var enc = null;
 
        if (c1 < 128) {
            end++;
        } else if((c1 > 127) && (c1 < 2048)) {
            enc = String.fromCharCode((c1 >> 6) | 192) + String.fromCharCode((c1 & 63) | 128);
        } else {
            enc = String.fromCharCode((c1 >> 12) | 224) + String.fromCharCode(((c1 >> 6) & 63) | 128) + String.fromCharCode((c1 & 63) | 128);
        }
        if (enc !== null) {
            if (end > start) {
                utftext += string.substring(start, end);
            }
            utftext += enc;
            start = end = n+1;
        }
    }
 
    if (end > start) {
        utftext += string.substring(start, string.length);
    }
 
    return utftext;
}  //ENDFUNCTION [utf8_encode]

function htmlspecialchars (string, quote_style) {
    // http://kevin.vanzonneveld.net
    // -    depends on: get_html_translation_table
    // *     example 1: htmlspecialchars("<a href='test'>Test</a>", 'ENT_QUOTES');
    // *     returns 1: '&lt;a href=&#039;test&#039;&gt;Test&lt;/a&gt;'
 
    var histogram = {}, symbol = '', tmp_str = '', entity = '';
    tmp_str = string.toString();
    
    if (false === (histogram = this.get_html_translation_table('HTML_SPECIALCHARS', quote_style))) {
        return false;
    }
    
    histogram["'"] = '&#039;';
    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(symbol).join(entity);
    }
    
    return tmp_str;
}

/* Parameters:
    * table
      There are two new constants (HTML_ENTITIES, HTML_SPECIALCHARS) that allow you to specify the table you want. 
      Default value for table is HTML_SPECIALCHARS.
    * quote_style
      Like the htmlspecialchars() and htmlentities() functions you can optionally specify the quote_style you are working with. 
      The default is ENT_COMPAT mode. 
      See the description of these modes in htmlspecialchars().
*/    
function get_html_translation_table(table, quote_style) {
    // http://kevin.vanzonneveld.net
    // %          note: It has been decided that we're not going to add global
    // %          note: dependencies to php.js. Meaning the constants are not
    // %          note: real constants, but strings instead. integers are also supported if someone
    // %          note: chooses to create the constants themselves.
    // *     example 1: get_html_translation_table('HTML_SPECIALCHARS');
    // *     returns 1: {'"': '&quot;', '&': '&amp;', '<': '&lt;', '>': '&gt;'}
    var entities = {}, histogram = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};
    
    // Translate arguments
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';
 
    useTable       = !isNaN(table) ? constMappingTable[table] : table ? table.toUpperCase() : 'HTML_SPECIALCHARS';
    useQuoteStyle = !isNaN(quote_style) ? constMappingQuoteStyle[quote_style] : quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT';
 
    if (useTable !== 'HTML_SPECIALCHARS' && useTable !== 'HTML_ENTITIES') {
        throw new Error("Table: "+useTable+' not supported');
        // return false;
    }
 
    if (useTable === 'HTML_ENTITIES') {
        entities['160'] = '&nbsp;';
        entities['161'] = '&iexcl;';
        entities['162'] = '&cent;';
        entities['163'] = '&pound;';
        entities['164'] = '&curren;';
        entities['165'] = '&yen;';
        entities['166'] = '&brvbar;';
        entities['167'] = '&sect;';
        entities['168'] = '&uml;';
        entities['169'] = '&copy;';
        entities['170'] = '&ordf;';
        entities['171'] = '&laquo;';
        entities['172'] = '&not;';
        entities['173'] = '&shy;';
        entities['174'] = '&reg;';
        entities['175'] = '&macr;';
        entities['176'] = '&deg;';
        entities['177'] = '&plusmn;';
        entities['178'] = '&sup2;';
        entities['179'] = '&sup3;';
        entities['180'] = '&acute;';
        entities['181'] = '&micro;';
        entities['182'] = '&para;';
        entities['183'] = '&middot;';
        entities['184'] = '&cedil;';
        entities['185'] = '&sup1;';
        entities['186'] = '&ordm;';
        entities['187'] = '&raquo;';
        entities['188'] = '&frac14;';
        entities['189'] = '&frac12;';
        entities['190'] = '&frac34;';
        entities['191'] = '&iquest;';
        entities['192'] = '&Agrave;';
        entities['193'] = '&Aacute;';
        entities['194'] = '&Acirc;';
        entities['195'] = '&Atilde;';
        entities['196'] = '&Auml;';
        entities['197'] = '&Aring;';
        entities['198'] = '&AElig;';
        entities['199'] = '&Ccedil;';
        entities['200'] = '&Egrave;';
        entities['201'] = '&Eacute;';
        entities['202'] = '&Ecirc;';
        entities['203'] = '&Euml;';
        entities['204'] = '&Igrave;';
        entities['205'] = '&Iacute;';
        entities['206'] = '&Icirc;';
        entities['207'] = '&Iuml;';
        entities['208'] = '&ETH;';
        entities['209'] = '&Ntilde;';
        entities['210'] = '&Ograve;';
        entities['211'] = '&Oacute;';
        entities['212'] = '&Ocirc;';
        entities['213'] = '&Otilde;';
        entities['214'] = '&Ouml;';
        entities['215'] = '&times;';
        entities['216'] = '&Oslash;';
        entities['217'] = '&Ugrave;';
        entities['218'] = '&Uacute;';
        entities['219'] = '&Ucirc;';
        entities['220'] = '&Uuml;';
        entities['221'] = '&Yacute;';
        entities['222'] = '&THORN;';
        entities['223'] = '&szlig;';
        entities['224'] = '&agrave;';
        entities['225'] = '&aacute;';
        entities['226'] = '&acirc;';
        entities['227'] = '&atilde;';
        entities['228'] = '&auml;';
        entities['229'] = '&aring;';
        entities['230'] = '&aelig;';
        entities['231'] = '&ccedil;';
        entities['232'] = '&egrave;';
        entities['233'] = '&eacute;';
        entities['234'] = '&ecirc;';
        entities['235'] = '&euml;';
        entities['236'] = '&igrave;';
        entities['237'] = '&iacute;';
        entities['238'] = '&icirc;';
        entities['239'] = '&iuml;';
        entities['240'] = '&eth;';
        entities['241'] = '&ntilde;';
        entities['242'] = '&ograve;';
        entities['243'] = '&oacute;';
        entities['244'] = '&ocirc;';
        entities['245'] = '&otilde;';
        entities['246'] = '&ouml;';
        entities['247'] = '&divide;';
        entities['248'] = '&oslash;';
        entities['249'] = '&ugrave;';
        entities['250'] = '&uacute;';
        entities['251'] = '&ucirc;';
        entities['252'] = '&uuml;';
        entities['253'] = '&yacute;';
        entities['254'] = '&thorn;';
        entities['255'] = '&yuml;';
    }
 
    if (useQuoteStyle !== 'ENT_NOQUOTES') {
        entities['34'] = '&quot;';
    }
    if (useQuoteStyle === 'ENT_QUOTES') {
        entities['39'] = '&#39;';
    }
    entities['60'] = '&lt;';
    entities['62'] = '&gt;';
 
    // ascii decimals for better compatibility
    entities['38'] = '&amp;';
 
    // ascii decimals to real symbols
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal);
        histogram[symbol] = entities[decimal];
    }
    
    return histogram;
}  //ENDFUNCTION [get_html_translation_table] (used by html_special_characters)

/*  UNUSED as of 19-Jun-09
//md5 hash
function md5(str) {
    // http://kevin.vanzonneveld.net
    // *     example 1: md5('Kevin van Zonneveld');
    // *     returns 1: '6e658d4bfcb59cc13f96c14450ac40b9'
 
    var xl;
    var rotateLeft = function(lValue, iShiftBits) {
        return (lValue<<iShiftBits) | (lValue>>>(32-iShiftBits));
    };
 
    var addUnsigned = function(lX,lY) {
        var lX4,lY4,lX8,lY8,lResult;
        lX8 = (lX & 0x80000000);
        lY8 = (lY & 0x80000000);
        lX4 = (lX & 0x40000000);
        lY4 = (lY & 0x40000000);
        lResult = (lX & 0x3FFFFFFF)+(lY & 0x3FFFFFFF);
        if (lX4 & lY4) {
            return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
        }
        if (lX4 | lY4) {
            if (lResult & 0x40000000) {
                return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
            } else {
                return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
            }
        } else {
            return (lResult ^ lX8 ^ lY8);
        }
    };
 
    var _F = function(x,y,z) { return (x & y) | ((~x) & z); };
    var _G = function(x,y,z) { return (x & z) | (y & (~z)); };
    var _H = function(x,y,z) { return (x ^ y ^ z); };
    var _I = function(x,y,z) { return (y ^ (x | (~z))); };
 
    var _FF = function(a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var _GG = function(a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var _HH = function(a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var _II = function(a,b,c,d,x,s,ac) {
        a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
        return addUnsigned(rotateLeft(a, s), b);
    };
 
    var convertToWordArray = function(str) {
        var lWordCount;
        var lMessageLength = str.length;
        var lNumberOfWords_temp1=lMessageLength + 8;
        var lNumberOfWords_temp2=(lNumberOfWords_temp1-(lNumberOfWords_temp1 % 64))/64;
        var lNumberOfWords = (lNumberOfWords_temp2+1)*16;
        var lWordArray=new Array(lNumberOfWords-1);
        var lBytePosition = 0;
        var lByteCount = 0;
        while ( lByteCount < lMessageLength ) {
            lWordCount = (lByteCount-(lByteCount % 4))/4;
            lBytePosition = (lByteCount % 4)*8;
            lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount)<<lBytePosition));
            lByteCount++;
        }
        lWordCount = (lByteCount-(lByteCount % 4))/4;
        lBytePosition = (lByteCount % 4)*8;
        lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80<<lBytePosition);
        lWordArray[lNumberOfWords-2] = lMessageLength<<3;
        lWordArray[lNumberOfWords-1] = lMessageLength>>>29;
        return lWordArray;
    };
 
    var wordToHex = function(lValue) {
        var wordToHexValue="",wordToHexValue_temp="",lByte,lCount;
        for (lCount = 0;lCount<=3;lCount++) {
            lByte = (lValue>>>(lCount*8)) & 255;
            wordToHexValue_temp = "0" + lByte.toString(16);
            wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length-2,2);
        }
        return wordToHexValue;
    };
 
    var x=[],
        k,AA,BB,CC,DD,a,b,c,d,
        S11=7, S12=12, S13=17, S14=22,
        S21=5, S22=9 , S23=14, S24=20,
        S31=4, S32=11, S33=16, S34=23,
        S41=6, S42=10, S43=15, S44=21;
 
    str = this.utf8_encode(str);
    x = convertToWordArray(str);
    a = 0x67452301; b = 0xEFCDAB89; c = 0x98BADCFE; d = 0x10325476;
    
    xl = x.length;
    for (k=0;k<xl;k+=16) {
        AA=a; BB=b; CC=c; DD=d;
        a=_FF(a,b,c,d,x[k+0], S11,0xD76AA478);
        d=_FF(d,a,b,c,x[k+1], S12,0xE8C7B756);
        c=_FF(c,d,a,b,x[k+2], S13,0x242070DB);
        b=_FF(b,c,d,a,x[k+3], S14,0xC1BDCEEE);
        a=_FF(a,b,c,d,x[k+4], S11,0xF57C0FAF);
        d=_FF(d,a,b,c,x[k+5], S12,0x4787C62A);
        c=_FF(c,d,a,b,x[k+6], S13,0xA8304613);
        b=_FF(b,c,d,a,x[k+7], S14,0xFD469501);
        a=_FF(a,b,c,d,x[k+8], S11,0x698098D8);
        d=_FF(d,a,b,c,x[k+9], S12,0x8B44F7AF);
        c=_FF(c,d,a,b,x[k+10],S13,0xFFFF5BB1);
        b=_FF(b,c,d,a,x[k+11],S14,0x895CD7BE);
        a=_FF(a,b,c,d,x[k+12],S11,0x6B901122);
        d=_FF(d,a,b,c,x[k+13],S12,0xFD987193);
        c=_FF(c,d,a,b,x[k+14],S13,0xA679438E);
        b=_FF(b,c,d,a,x[k+15],S14,0x49B40821);
        a=_GG(a,b,c,d,x[k+1], S21,0xF61E2562);
        d=_GG(d,a,b,c,x[k+6], S22,0xC040B340);
        c=_GG(c,d,a,b,x[k+11],S23,0x265E5A51);
        b=_GG(b,c,d,a,x[k+0], S24,0xE9B6C7AA);
        a=_GG(a,b,c,d,x[k+5], S21,0xD62F105D);
        d=_GG(d,a,b,c,x[k+10],S22,0x2441453);
        c=_GG(c,d,a,b,x[k+15],S23,0xD8A1E681);
        b=_GG(b,c,d,a,x[k+4], S24,0xE7D3FBC8);
        a=_GG(a,b,c,d,x[k+9], S21,0x21E1CDE6);
        d=_GG(d,a,b,c,x[k+14],S22,0xC33707D6);
        c=_GG(c,d,a,b,x[k+3], S23,0xF4D50D87);
        b=_GG(b,c,d,a,x[k+8], S24,0x455A14ED);
        a=_GG(a,b,c,d,x[k+13],S21,0xA9E3E905);
        d=_GG(d,a,b,c,x[k+2], S22,0xFCEFA3F8);
        c=_GG(c,d,a,b,x[k+7], S23,0x676F02D9);
        b=_GG(b,c,d,a,x[k+12],S24,0x8D2A4C8A);
        a=_HH(a,b,c,d,x[k+5], S31,0xFFFA3942);
        d=_HH(d,a,b,c,x[k+8], S32,0x8771F681);
        c=_HH(c,d,a,b,x[k+11],S33,0x6D9D6122);
        b=_HH(b,c,d,a,x[k+14],S34,0xFDE5380C);
        a=_HH(a,b,c,d,x[k+1], S31,0xA4BEEA44);
        d=_HH(d,a,b,c,x[k+4], S32,0x4BDECFA9);
        c=_HH(c,d,a,b,x[k+7], S33,0xF6BB4B60);
        b=_HH(b,c,d,a,x[k+10],S34,0xBEBFBC70);
        a=_HH(a,b,c,d,x[k+13],S31,0x289B7EC6);
        d=_HH(d,a,b,c,x[k+0], S32,0xEAA127FA);
        c=_HH(c,d,a,b,x[k+3], S33,0xD4EF3085);
        b=_HH(b,c,d,a,x[k+6], S34,0x4881D05);
        a=_HH(a,b,c,d,x[k+9], S31,0xD9D4D039);
        d=_HH(d,a,b,c,x[k+12],S32,0xE6DB99E5);
        c=_HH(c,d,a,b,x[k+15],S33,0x1FA27CF8);
        b=_HH(b,c,d,a,x[k+2], S34,0xC4AC5665);
        a=_II(a,b,c,d,x[k+0], S41,0xF4292244);
        d=_II(d,a,b,c,x[k+7], S42,0x432AFF97);
        c=_II(c,d,a,b,x[k+14],S43,0xAB9423A7);
        b=_II(b,c,d,a,x[k+5], S44,0xFC93A039);
        a=_II(a,b,c,d,x[k+12],S41,0x655B59C3);
        d=_II(d,a,b,c,x[k+3], S42,0x8F0CCC92);
        c=_II(c,d,a,b,x[k+10],S43,0xFFEFF47D);
        b=_II(b,c,d,a,x[k+1], S44,0x85845DD1);
        a=_II(a,b,c,d,x[k+8], S41,0x6FA87E4F);
        d=_II(d,a,b,c,x[k+15],S42,0xFE2CE6E0);
        c=_II(c,d,a,b,x[k+6], S43,0xA3014314);
        b=_II(b,c,d,a,x[k+13],S44,0x4E0811A1);
        a=_II(a,b,c,d,x[k+4], S41,0xF7537E82);
        d=_II(d,a,b,c,x[k+11],S42,0xBD3AF235);
        c=_II(c,d,a,b,x[k+2], S43,0x2AD7D2BB);
        b=_II(b,c,d,a,x[k+9], S44,0xEB86D391);
        a=addUnsigned(a,AA);
        b=addUnsigned(b,BB);
        c=addUnsigned(c,CC);
        d=addUnsigned(d,DD);
    }
 
    var temp = wordToHex(a)+wordToHex(b)+wordToHex(c)+wordToHex(d);
    return temp.toLowerCase();
}  //ENDFUNCTION [md5]
*/
