function ywUtil() { //container for utility functions
}
ywUtil.CreateRequest = function() {
   var request;
   try {
      request = new XMLHttpRequest();
   }
   catch (tryMS) {
      try {
         request = new ActiveXOjbect( "Msxml2.XMLHTTP" );
      }
      catch (otherMS) {
         try {
            request = new ActiveXOjbect( "Microsoft.XMLHTTP" );
         }
         catch (failed) {
            request = null;
         }
      }
   }
   return request;
};

//all in one create request, send, check status ala Flanagan 5th ed.
//
ywUtil.SendRequest = function( url, post, callback ) {
	var request = this.CreateRequest();
	request.onreadystatechange = function() {
		if (request.readyState == 4 && request.status == 200)
			callback( request.responseText );
	};
	
	if (post) {
		request.open( 'POST', url, true );
		request.setRequestHeader('Content-Type',
			'application/x-www-form-urlencoded' );
	}
	else {
		request.open( 'GET', url, true );
	}
	request.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
	request.send( post );
};

ywUtil.Pathname = function() {
	var path = window.location.pathname;
	return path.slice( 1, path.lastIndexOf( '/' ) + 1 );
};

ywUtil.Encode = function( value ) {
	var regx = /%20/g;
	return encodeURIComponent( value ).replace( regx, '+' );
};
ywUtil.Decode = function( value ) {
	return decodeURIComponent( value.replace( '+', '%20' ) );
};
ywUtil.DecodeCategory = function( rawCategory ) {
	var pieces = rawCategory.split( '_' );
	
	for (var i = 0; i < pieces.length; i++ ) {
		pieces[i] = pieces[i].substring(0, 1).toUpperCase() +
			pieces[i].substring(1);
	}

	return pieces.join( ' ' );
};
ywUtil.trim = function( str ) {
	return str.replace( /^\s+|\s+$/g, '' );
};

//methods to simulate PHP $_GET[] using location.hash instead of
//location.search so back button & bookmarks work without page reload
ywUtil.GetHash = function( name ) {
	if (window.location.hash) { //hash contains the query
		var query = window.location.hash.split( '?' );
		if (query[1]) {
			var pattern = new RegExp( name + '=([a-zA-Z0-9_+]+)' );
			var parse = query[1].match( pattern );
			if (parse) {
				return parse[1];
			}
		}
	}
	return null;
};
ywUtil.SetHash = function( name, value ) {
	if (window.location.hash) { //hash contains the query
		var query = window.location.hash.split( '?' );
		if (query[1]) { //if query exists
			var pattern = new RegExp( name + '=([a-zA-Z0-9_+]+)' );
			var parse = query[1].replace( pattern, name + '=' + value );
			if (parse != query[1]) { //update existing query
				window.location.replace( query[0] + '?' + parse );
			}
			else { //add new query
				window.location.replace( query[0] + '?' + query[1] +
					'&' + name + '=' + value );
			}
		}
		else {
			window.location.replace( window.location.hash +
					'?' + name + '=' + value );
		}
	}
	else {
		window.location.replace( window.location.href + '#' +
				'?' + name + '=' + value );
	}
};

ywUtil.AddHandler = function( element, event, handler ) {
	if (element.addEventListener) {
		element.addEventListener( event, handler, false );
	}
	else {
		element.attachEvent( 'on' + event, handler );	
	}
};
ywUtil.RemoveHandler = function( element, event, handler ) {
	if (element.removeEventListener) {
		element.removeEventListener( event, handler, false );
	}
	else {
		element.detachEvent( 'on' + event, handler );	
	}
};

ywUtil.ScheduleHandler = function( handler ) {
	this.AddHandler( window, 'load', handler );
};
ywUtil.UnscheduleHandler = function( handler ) {
	this.RemoveHandler( window, 'load', handler );
};

ywUtil.ScrollHere = function() {
	if (this.GetGlobal( 'scrollhere' )) {
		var here = document.getElementById( this.GetGlobal( 'scrollhere' ) );
		if (here) {
			here.scrollIntoView(true);
		}
	}
};

//nice hack to change an attribute during loading if possible,
//else attach handler to do so
//in particular, it can make an element invisible on a page-by-page basis
ywUtil.ChangeClassById = function( id, newClass ) {
	if ( document.getElementById( id ) ) {
		document.getElementById( id ).className = newClass;
	}
	else {
		ywUtil.ScheduleHandler( function() {
			document.getElementById( id ).className = newClass;
		} );
	}
};

//incoming 'GET' methods
ywUtil._GET = {};

if (window.location.search) {
	var query = ( window.location.search.slice( 1 ) ).split( '&' );
	for (var i = 0; i < query.length; i++) {
		var parse = query[i].split( '=' );
		ywUtil._GET[parse[0]] = ywUtil.Decode( parse[1] );
	}
}
ywUtil.Get_GET = function( name ) {
	return (this._GET[name])? this._GET[name]: null;
};
ywUtil.Unset_GET = function( name ) {
	this._GET[name] = null;
};

//outgoing 'POST' methods following Mental Jetsam's Peter Finch's example
ywUtil.newPost = {};
ywUtil.AppendToPost = function( name, value ) {
	this.newPost[name] = value;
};
ywUtil.SubmitPost = function( url ) {
	var postForm = document.createElement("form");
	postForm.method="post";
	postForm.action = url;
	for (var name in this.newPost) {
		var val = this.newPost[name];
		if (typeof( val ) != "object") {
			var input = document.createElement("input");
			input.name = name;
			input.value = val;
			input.type = 'hidden';
			postForm.appendChild(input);
		}
		else {
			name += '[]';
			for (var i = 0; i < val.length; i++) {
				input = document.createElement("input");
				input.name = name;
				input.value = val[i];
				input.type = 'hidden';
				postForm.appendChild(input);				
			}
		}
	}		

	document.body.appendChild(postForm);
	postForm.submit();
	document.body.removeChild(postForm); //not sure why this executes :(
};

//storage for globals; use freely!
ywUtil.globals = {};
ywUtil.SetGlobal = function( name, value ) {
	this.globals[name] = value;
};
ywUtil.GetGlobal = function( name ) {
	return this.globals[name];
};
ywUtil.redirect = function( name, dont_replace ) {
    var host = 'http://' + location.hostname;
    var path = location.pathname.replace(/^(.*\/)[^\/]+$/, '$1');
    if (arguments.length)
    	path += name;
    if (arguments.length <2)
    	location.replace( host + path );
    else
    	location.href = host + path;
};
ywUtil.objLeftTop = function( obj ) {
	var oleft = otop = 0;
	if (obj.offsetParent) {
		do {
			oleft += obj.offsetLeft;
			otop += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	return [oleft,otop];
};