// HELP/INFO/DEVELOPER CONTACT: jose@jcao.com


	//// OBJECT CLASS FOR GETTING INFORMATION ABOUT THE USERS BROWSER/ENVIRONMENT
		function clientApp() {
			var classRoot   = this;
		// get the usual browser identification strings, make the lowercase, and easier to parse.
			classRoot.agent      = navigator.userAgent.toLowerCase();
			classRoot.name       = navigator.appName.toLowerCase();
			classRoot.version    = navigator.appVersion.toLowerCase();
			classRoot.system     = navigator.platform.toLowerCase();
			classRoot.engine     = false;
		// test for various operating strings via non object-based test
			if (classRoot.system == 'macppc' || classRoot.system == 'intel') { classRoot.OS = 'mac';        }
			if (classRoot.system == 'win32' || classRoot.system == 'win64')  { classRoot.OS = 'win';        }
			if (classRoot.agent.indexOf(' linux') != -1)                     { classRoot.OS = 'linux';      }
			if (!classRoot.OS)                                               { classRoot.OS = false;        }
		// test for rendering engine (not browser) via object-based test
			try { if (navigator.product.toLowerCase() == 'gecko')            { classRoot.engine = 'gecko';  }} catch (e) {}
			try { if ((document.childNodes) && (!navigator.taintEnabled))    { classRoot.engine = 'webkit'; }} catch (e) {}
			try { if (typeof(window.opera) == 'object')                      { classRoot.engine = 'opera';  }} catch (e) {}
			try { if (typeof(window.ScriptEngine) == 'function')             { classRoot.engine = 'icab';   }} catch (e) {}
			try { if (typeof(ActiveXObject) == 'function')                   { classRoot.engine = 'msie';   }} catch (e) {}
			if (!classRoot.engine)                                           { classRoot.engine = false;                 }
		// get rendering engine revision # agent-based tests, by specific rendering engine
			switch(classRoot.engine){
				case 'webkit' : classRoot.engRev = classRoot.agent.split(' applewebkit/')[1].split(' (khtml')[0];       break;
				case 'gecko'  : classRoot.engRev = classRoot.agent.split(') gecko/')[1].split(' ')[0];                  break;
				case 'opera'  : classRoot.engRev = classRoot.agent.split('opera')[1].substring(1).split(' (')[0];       break;
				case 'icab'   : classRoot.engRev = classRoot.engRev = classRoot.agent.split(' icab ')[1].split(';')[0]; break;
				case 'msie'   : classRoot.engRev = classRoot.engRev = classRoot.agent.split(' msie ')[1].split(';')[0]; break;
				case false    : classRoot.engRev = false;                                                               break;
			}
		// test for browsers via non object-based test
		// mozilla must come first, because 'mozilla/' appears in many other more specific gecko browsers
			if (classRoot.agent.indexOf('mozilla/') != -1)                   { classRoot.app = 'mozilla';    }
			if (classRoot.engine == 'msie')                                  { classRoot.app = 'msie';       }
			if (classRoot.agent.indexOf(' netscape6/') != -1)                { classRoot.app = 'netscape';   }
			if (classRoot.agent.indexOf(' netscape/') != -1)                 { classRoot.app = 'netscape';   }
			if (classRoot.agent.indexOf(' safari/') != -1)                   { classRoot.app = 'safari';     }
			if (classRoot.agent.indexOf('safari) omniweb/') != -1)           { classRoot.app = 'omniweb';    }
			if (classRoot.agent.indexOf(' gecko) shiira') != -1)             { classRoot.app = 'shiira';     }
			if (classRoot.agent.indexOf(' camino/') != -1)                   { classRoot.app = 'camino';     }
			if (classRoot.agent.indexOf('konqueror/') != -1)                 { classRoot.app = 'konqueror';  }
			if (classRoot.agent.indexOf(' firefox/') != -1)                  { classRoot.app = 'firefox';    }
			if (classRoot.agent.indexOf('opera') != -1)                      { classRoot.app = 'opera';      }
			if (classRoot.engine == 'icab')                                  { classRoot.app = 'icab';       }
			if (!classRoot.app)                                              { classRoot.app = false;        }
		// then get browser version, using the best method for this browser.
			switch(classRoot.app){
				case 'mozilla'   : classRoot.appRev = classRoot.agent.split(' rv:')[1].split(') ')[0];                     break;
				case 'msie'      : classRoot.appRev = classRoot.engRev = classRoot.agent.split(' msie ')[1].split(';')[0]; break;
				case 'safari'    : classRoot.appRev = classRoot.agent.split(' safari/')[1];                                break;
				case 'omniweb'   : classRoot.appRev = classRoot.agent.split('omniweb/v')[1];                               break;
				case 'shiira'    : classRoot.appRev = classRoot.agent.split('shiira/')[1].split(' safari')[0];             break;
				case 'camino'    : classRoot.appRev = classRoot.agent.split('camino/')[1];                                 break;
				// netscape's user agent strings are a mess ...
				case 'netscape'  : classRoot.appRev = (classRoot.agent.indexOf(' netscape6/') != -1) ? classRoot.agent.split(' netscape6/')[1] : classRoot.agent.split(' netscape/')[1]; break;
				case 'navigator' : classRoot.appRev = classRoot.agent.split('ozilla/')[1].split(' ')[0].split('-')[0];     break;
				case 'konqueror' : classRoot.appRev = classRoot.agent.split(' konqueror/')[1].split(';')[0].split('-')[0]; break;
				case 'firefox'   : classRoot.appRev = classRoot.agent.split(' firefox/')[1];                               break;
				case 'opera'     : classRoot.appRev = classRoot.engRev;                                                    break;
				case 'icab'      : classRoot.appRev = classRoot.engRev = classRoot.agent.split(' icab ')[1].split(';')[0]; break;
				case false       : classRoot.appRev =  false;                                                              break;
			}
		// some object-based tests for basic DOM support
			classRoot.supportsDom = (
				typeof(document.getElementById)                  != 'undefined' &&
				typeof(document.getElementsByTagName)            != 'undefined' &&
				typeof(document.nextSibling)                     != 'undefined' &&
				typeof(document.previousSibling)                 != 'undefined' &&
				typeof(document.childNodes)                      != 'undefined' &&
				typeof(document.parentNode)                      != 'undefined' &&
				typeof(document.hasChildNodes)                   != 'undefined' &&
				typeof(document.nodeType)                        != 'undefined' &&
				typeof(document.cloneNode)                       != 'undefined' &&
				typeof(document.insertBefore)                    != 'undefined' &&
				typeof(document.appendChild)                     != 'undefined' &&
				typeof(document.removeChild)                     != 'undefined' &&
				typeof(document.replaceChild)                    != 'undefined' &&
				typeof(document.documentElement.tagName)         != 'undefined' &&
				typeof(document.documentElement.getAttribute)    != 'undefined' &&
				typeof(document.documentElement.removeAttribute) != 'undefined' &&
				typeof(document.documentElement.attributes)      != 'undefined'
			) ? true : false;
		// get the viewport* width and height *(the usable interior dimensions of the browser window that does not include any browser chrome);
			classRoot.viewportX     = viewportX();
			classRoot.viewportY     = viewportY();
			// update values on window resize event ...
			window.onresize = function() { classRoot.viewportX  = viewportX();  }
			window.onresize = function() { classRoot.viewportY = viewportY(); }
		// screen resolution (total, including menubar/taskbar etc...)
			classRoot.screenX       = screen.width;
			classRoot.screenY       = screen.height;
		// screen resolution (total available for use)
			classRoot.screenAvailY  = screen.availWidth;
			classRoot.screenAvailX  = screen.availHeight;
		}




	//// GET VIEWPORT WIDTH
		function viewportX(windowName) {
			try {
				if (!windowName) { var windowName = 'self' };
				if (self.innerHeight) {
					var widthProperty = '.innerWidth';
				} else if (document.body) {
					var widthProperty = '.document.body.clientWidth';
				} else if (document.documentElement && document.documentElement.clientHeight) {
					var widthProperty = '.document.documentElement.clientWidth';
				}
				eval('var viewportX = ' + windowName + widthProperty);
			} catch (e) {
				var viewportX = false;
			}
			return viewportX;
		}




	//// GET VIEWPORT HEIGHT
		function viewportY(windowName) {
			try {
				if (!windowName) { var windowName = 'self' };
				if (self.innerHeight) {
					var heightProperty = '.innerHeight';
				} else if (document.body) {
					var heightProperty = '.document.body.clientHeight';
				} else if (document.documentElement && document.documentElement.clientHeight) {
					var heightProperty = '.document.documentElement.clientHeight';
				}
				eval('var viewportY = ' + windowName + heightProperty);
			} catch (e) {
				var viewportY = false;
			}
			return viewportY;
		}




	//// GET WINDOW POSITION (X)
		function winPosX(windowName) {
			if (!windowName) { var windowName = 'self' };
			if (window.screenLeft) {
				var pos = eval(windowName + '.screenLeft');
			} else if (window.screenX) {
				var pos = eval(windowName + '.screenX');
			} else {
				var pos = false;
			}
			return pos;
		}




	//// GET WINDOW POSITION (Y)
		function winPosY(windowName) {
			if (!windowName) { var windowName = 'self' };
			if (window.screenTop) {
				var pos = eval(windowName + '.screenTop');
			} else if (window.screenY) {
				var pos = eval(windowName + '.screenY');
			} else {
				var pos = false;
			}
			return pos;
		}




	//// INITIALIZE THE clientApp OBJECT
		var client = new clientApp();