
/*! * * * * * * * * * * * * * * * * * * * * * * * * * *\

    Petrofied
    Copyright (c) 2009-2010, Petro M. Salema
    petro@petrosalema.com

\* * * * * * * * * * * * * * * * * * * * * * * * * * */

var Petrofied = {
	version: '1.7'
};

/**
 * If prop is specified, returns index of prop with value of needle in this
 * Array if successful; otherwise -1
 */
Array.prototype.indexOf = function ( needle, prop )
{
	var l = this.length,
		i = 0;
	
	if ( prop )
	{
		for ( ; i < l; i++ )
			if ( this[i][ prop ] === needle )
				return i;
	}
	else
	{
		for ( ; i < l; i++ )
			if ( this[i] === needle )
				return i;
	}
	
	return -1;
};

/**
 * Removes element needle from array and returns it
 */
Array.prototype.pluck = function ( needle )
{
	var i = this.indexOf( needle ),
		r = this[i];
	this.splice( i, 1 );
	return r;
}

/**
 * Give all functions the ability to return a clone of themselves bound to
 * the variable scope of "object"
 */
Function.prototype.bind = function ()
{
	var args = Util.argsToArray( arguments ),
		object = args.shift(),
		method = this; 
	return function ()
	{ return method.apply( object, args.concat( Util.argsToArray( arguments ) ) ); }
}

/**
 * Similar to "bind" but passes that the event object as first parameter
 */
Function.prototype.bindWithEvent = function ()
{
	var args = Util.argsToArray( arguments ),
		object = args.shift(),
		method = this; 
	return function ( event )
	{ return method.apply( object, [event || window.event].concat( args ) ); }
}

Number.prototype.bound = function ( min, max )
{ return Math.max( ( min || this ), Math.min( ( max || this ), this ) ); }

String.prototype.stripTags = function ()
{ return this.replace( /<\/?[^>]+>/gi, '' ); }

String.prototype.tagsToHTML = function ()
{ return this.replace( '<', '&lt;' ).replace( '>', '&gt;' ); }

/**
 * Will turn "mary had_a little-lamb" to "maryHadALittleLamb"
 */
String.prototype.toCamelCase = function ()
{
	var str = this,
		chunks = str.replace( /-|_/g, ' ' )
					.replace( /\s+/g, ' ' )
					.split( ' ' ),
		camelized = chunks[0],
		i = 1,
		s;
	
	for ( ; i < chunks.length; i++ )
	{
		s = chunks[i];
		camelized += s.substring( 0, 1 ).toUpperCase()
				  +  s.substring( 1, s.length );
	}
	
	return camelized;
}

/**
 * Will turn "mary_had a Little-lamb" to "Mary_Had a Little-Lamb"
 */
String.prototype.toTitleCase = function ()
{
	var str = this,
		odd = /([\s\-_])/g,
		separator = '{-+toTitleChuckGap+-}',
		chunks = str.replace( odd, "$1" + separator ).split( separator ),
		ignore = [ 'to', 'it', 'on', 'the', 'a', 'and', 'or', 'nor', 'of', 'in' ],
		camelized = '',
		i = 0,
		s;
	
	for ( ; i < chunks.length; i++ )
	{
		s = chunks[i];
		camelized += ( ignore.indexOf( s.replace( odd, '' ) ) == -1 )
			? s.substring( 0, 1 ).toUpperCase() + s.substring( 1, s.length )
			: s;
	}
	
	return camelized;
}

String.prototype.trim = function ()
{ return this.replace( /^\s+/, '' ).replace( /\s+$/, '' ); }

function Class ()
{
	var args = Util.argsToArray( arguments ),
		methods = [],
		i = 0;
	
	/* These arguments are Objects which we will combine into a single
		Object */
	for ( ; i < args.length; i++ )
		if ( typeof args[i]  == 'object' )
			methods.push( args[i] );
	
	function _constructor ()
	{
		/* These are the arguments to be passed into the private _initialize
			function called on creation */
		var argsForInit = Util.argsToArray( arguments ),
			i = 0,
			key;
		
		/* Copy all our Objects' methods into _constructor */
		for ( ; i < methods.length; i++ )
			for ( key in methods[i] )
				this[ key ] = methods[i][ key ];
		
		/* Check if we have an _initialize function, if so call it thru
			"apply" and pass argsForInit to it */
		if ( this._initialize && typeof this._initialize == 'function' )
			this._initialize.apply( this, argsForInit );
	}
	
	/* Make sure we're using _constructor as our constructor */
	_constructor.constructor = _constructor;
	
	return _constructor;
}

/* * * * * * * * * * * Util functions * * * * * * * * * * */

/**
 * Create Util namespace
 */
var Util = { };

Util.addClass = function ( el, str )
{
	var rx = new RegExp( '(^|\\s)' + str + '(\\s|$)', 'g' );
	if ( !rx.test( el.className ) )
		el.className += ( el.className == '' ) ? str : ' ' + str;
}

/**
 * Attaches Event Listener for Event ev to Element el 
 */
Util.addEvent = function ( el, ev, fn )
{
	if ( !el )
		return;
	if ( document.addEventListener )
		el.addEventListener( ev, fn, false );
	else if ( document.attachEvent )
		el.attachEvent( 'on' + ev, fn );
}

Util.applyStyle = function ( el, styles )
{
	var camelCase;
	for ( var prop in styles )
	{
		camelCase = prop.replace(
				/\-(\w)/g,
				function( all, letter ) { return letter.toUpperCase(); }
			);
		el.style[ camelCase ] = styles[ prop ];
	}
}

Util.argsToArray = function ( args )
{ return Array.prototype.slice.apply( args ); }

/**
 * Creates and returns DOM element
 */
Util.createElement = function ( tag, content, id, className, context )
{
	var el = ( context || document ).createElement( tag );
	if ( id )
		el.setAttribute( 'id', id );
	if ( className )
		Util.addClass( el, className );
	if ( content )
		el.innerHTML = content;
	return el;
}

/**
 * Disable selecting
 */
Util.disableSelecting = function ( element )
{
	var el = element ||
		   ( document.body || document.getElementByTagName( 'body' )[0] );
	el.onselectstart = function () { return false; };
	el.unselectable = 'on';
	el.style.MozUserSelect = 'none';
	el.style.cursor = 'default';
}

/**
 * Reenable selecting
 */
Util.enableSelecting = function ( element )
{
	var el = element ||
		   ( document.body || document.getElementByTagName( 'body' )[0] );
	el.onselectstart = null;
	el.unselectable = 'off';
	el.style.MozUserSelect = '';
	el.style.cursor = 'auto';
}

Util.getChildAt = function ( box, index )
{
	var child;
	while ( child = box.childNodes[index] )
		if ( child.nodeName == '#text' )
			index++;
		else
			return child;
}

/**
 * Returns an Array of DOMElements containing the className name
 * within the DOMElement parent (if specified).
 * May also be constrained to looking for elements of type tags if specified
 */
Util.getElementsByClassName = function ( name, parent, tags )
{
	var node = parent || document,
		tags = tags ? tags.split( ' ' ) : [ '*' ],
		pattern = new RegExp( '(^|\\s)' + name + '(\\s|$)' ),
		elements = [],
		collection = [],
		results = [],
		i,
		el;
	
	while ( tags.length > 0 )
	{
		collection = node.getElementsByTagName( tags.shift() );
		for ( i = 0; i < collection.length; i++ )
			elements.push( collection[i] );
	}
	
	for ( el in elements )
		if ( pattern.test( elements[ el ].className ) )
			results.push( elements[ el ] );
	
	return results;
}

/**
 * Returns parent Element of property el[k] = v
 */
Util.getElementsByProperties = function ( props, scope, tagName )
{
	var test = false,
		elements = ( scope || document )
					.getElementsByTagName( tagName || '*' ),
		collection = [],
		el,
		i = 0,
		k;
	
	for ( ; i < elements.length; i++ )
	{
		el = elements[i];
		
		for ( k in props )
		{
			if ( typeof( props[k] ) == 'string' )
				test = ( el[k] == props[k] );
			else
				test = props[k].test( el[k] );
			
			if ( !test ) /* If even just one property is false then we might as well forget the rest */
				break;
		}
		
		if ( test ) /* if TRUE we've hit BULLZEYE */
			collection.push( el );
		else
			continue;
	}
	return collection;	
}

Util.getDocHeight = function ()
{ return Util.getDocumentDimensions( 'Height' ); }

Util.getDocWidth = function ()
{ return Util.getDocumentDimensions( 'Width' ); }

Util.getDocumentDimensions = function ( name )
{
	return Math.max(
			document.documentElement[ 'client' + name ],
			document.body[ 'scroll' + name ],
			document.documentElement[ 'scroll' + name ],
			document.body[ 'offset' + name ],
			document.documentElement[ 'offset' + name ]
		);
}

/**
 * Returns and Object containing the x and y values of the cursors position
 */
Util.getMouse = function ( ev )
{
	var x = 0,
		y = 0;
	
	if ( !Util.isIE() )
	{
		x = ev.pageX;
		y = ev.pageY;
	}
	else
	{
		x = window.event.clientX;
		y = window.event.clientY + document.body.scrollTop;
	}
	
	return { x: x, y: y }
}

/**
 * Returns parent Element of property el[k] = v
 */
Util.getParent = function ( el, props )
{ 
	el = el.parentNode;
	
	var test = false,
		k;
	
	while ( el.tagName != undefined )
	{
		for ( k in props )
		{
			if ( typeof( props[k] ) == 'string' )
				test = ( el[k] == props[k] );
			else
				test = props[k].test( el[k] );
			if ( !test )
				break; /* If 1 property is false then we might as well forget the rest */
		}
		
		if ( test )
			break; /* if TRUE we've hit BULLZEYE */
		else
			el = el.parentNode;
	}
	
	return ( ( el.tagName == undefined ) ? null : el );	
}

/**
 *Returns source Element of tagname tag for Event e
 */
Util.getSrc = function ( e, match )
{
	var src = e.target || window.event.srcElement,
		regexp = ( typeof( match ) != 'string' ),
		tag = regexp ? match : match.toLowerCase();
	
	while ( src.tagName != undefined )
	{
		if ( regexp )
			if ( match.test( src.tagName.toLowerCase() ) )
				break;
		
		if ( src.tagName.toLowerCase() == tag )
			break;
		
		src = src.parentNode;
		
		if ( !src )
			break;
	}
	
	if ( !src )
		return null;
	else
		return ( ( src.tagName == undefined ) ? null : src );
}

/**
 * Returns String of Element el's style Property prop
 */
Util.getStyle = function ( el, prop )
{
	var style = '';
	
	try
	{
		if ( el.currentStyle )
		{
			/* Must convert style-side to styleSide for IE */
			prop = prop.toCamelCase();
			style = el.currentStyle[prop];
		}
		else
			style = document.defaultView.getComputedStyle( el, null )
							.getPropertyValue( prop );
	}
	catch( e ) {}
	
	return style;
}

/**
 * Returns an Object containing the window's x and y scroll values
 */
Util.getWindowScroll = function ()
{
	var x = 0,
		y = 0;
	
	if ( typeof ( window.pageYOffset ) == 'number' )
	{
		x = window.pageXOffset;
		y = window.pageYOffset;
	}
	else if ( document.body
			  && ( document.body.scrollLeft || document.body.scrollTop ) )
	{
		x = document.body.scrollLeft;
		y = document.body.scrollTop;
	}
	else if ( document.documentElement
			  && ( document.documentElement.scrollLeft
				   || document.documentElement.scrollTop ) )
	{
		x = document.documentElement.scrollLeft;
		y = document.documentElement.scrollTop;
	}

	return { x: (x || 0), y: (y || 0) }
}

/**
 * Returns an Object containing the height and width of the browser window
 */
Util.getWindowSize = function ()
{
	var w = 0,
		h = 0;
	
	if ( self.innerHeight )
	{
		w = self.innerWidth;
		h = self.innerHeight;
	}
	else if ( document.documentElement
			  && document.documentElement.clientHeight )
	{
		w = document.documentElement.clientWidth;
		h = document.documentElement.clientHeight;
	}
	else if ( document.body )
	{
		w = document.body.clientWidth;
		h = document.body.clientHeight;
	}
	return { width: w, height: h }
}

/**
 * Returns the real top and left values of element's position not its
 * contextual value
 */
Util.globalOffset = function ( element )
{
	var l = 0,
		t = 0;
	
	while ( element )
	{
		l += element.offsetLeft || 0;
		t += element.offsetTop  || 0;
		element = element.offsetParent;
	}
	
	return { left: l, top: t }
}

Util.hasClass = function ( el, str )
{
	var rx = new RegExp( '(^|\\s)' + str + '(\\s|$)', 'g' );
	return rx.test( el.className );
}

/**
 * Checks if object overlaps/intersects target. If three arguments are
 * passed object's t and l will be arguments 0 and 1 and objects w and h
 * will be 0 in order to present a pixel point as opposed to a box.
 */
Util.hitTest = function ()
{
	var a = arguments,
		t = a[2] || a[1],
		o = ( a.length == 3 ) ? { l: a[0], t: a[1], w: 0, h: 0 } : a[0],
		ot = Util.globalOffset(t),
		bt,
		oo,
		bo;
	
	if ( Util.isIE() )
		ot.l -= parseInt( document.body.scrollLeft ); 
	
	ot.w = t.offsetWidth;
	ot.h = t.offsetHeight;
	/* Target bounding box */
	bt = { l: ot.l, r: ot.l + ot.w, t: ot.t, b: ot.t + ot.h }
	
	if ( a.length == 3 )
		oo = o;
	else
	{
		oo = Util.globalOffset( o );
		oo.w = o.offsetWidth;
		oo.h = o.offsetHeight;
	}
	
	/* Object bounding box */
	bo = { l: oo.l, r: oo.l + oo.w, t: oo.t, b: oo.t + oo.h }
	
	return !!( bo.r > bt.l && bo.l < bt.r && bo.b > bt.t && bo.t < bt.b );
}

Util.insertAfter = function ( node, sibling )
{
	if ( sibling.nextSibling )
		sibling.parentNode.insertBefore( node, sibling.nextSibling );
	else
		sibling.parentNode.appendChild( node );
}

Util.isIE = function ()
{ return !( document.getElementById && !document.all ); }

Util.json = function ( data )
{
	var json = false;
	try { json = eval( '(' + data + ')' ); } catch( e ) {}
	return json;
}

/**
 * Removes Event Listener for Event type from Element el
 */
Util.removeEvent = function ( el, type, fn )
{
	if ( !el )
		return;
	
	if ( document.addEventListener )
		el.removeEventListener( type, fn, false );
	else if ( document.attachEvent )
		el.detachEvent('on' + type, fn );
}

Util.removeClass = function ( el, str )
{
	var rx = new RegExp( '(^|\\s)' + str + '(\\s|$)', 'g' );
	el.className = el.className.replace( rx, '$1$2' );
}

/**
 * Removes DOM Node node and returns it
 */
Util.removeNode = function ( node )
{
	var el = ( typeof( node ) == 'string' )
		? document.getElementById( node ) : node;
	el.parentNode.removeChild( el );
	return el;
};

Util.setStyle = function ( el, prop, value )
{
	if ( prop == 'alpha' )
	{
		var a = parseFloat( value )
		el.style.opacity = '' + a;
		el.style.filter = 'alpha(opacity=' + ( a * 100 ) + ')';
	}
	else
		el.style[Util.camelize( prop )] = value;
}

/**
 * For debugging(same as PHP function)
 */
var_dump = function ( obj, name, depth, maxDepths )
{ 
	var maxDepth = maxDepths || 1;
	
	if ( !/(object)|(array)/.test( typeof obj ) || depth > maxDepth )
		return obj;
	
	var map = ( name || '[Object]' ) + ' {\n',
		i,
		o,
		t = '\t',
		depth = depth || 0;
	
	for ( i = 0; i < depth; i++ )
		t += '\t';
	
	depth++;
	
	for ( i in obj )
	{
		o = obj[i];
		
		map += t + i + ' => '
			+ ( /(object)|(array)/.test( typeof o )
				? var_dump( o, null, depth, maxDepth ) : o )
			+ t + '\n';
	}
	
	map += '}';
	
	return map;
}

function $i ( id, doc )
{ return ( doc || document ).getElementById( id ); }

function $t ( tagName, parent )
{ return ( parent || document ).getElementsByTagName( tagName ); }

function $c ( className, parent, elements  )
{ return Util.getElementsByClassName( className, parent, elements ); }



/* * * * * * * * * * * * * * * * * * * * * * *\
 *											 *
 *	AJAX Module								 *
 *	  Copyright (c) 2010, Petro M. Salema	 *
 *	  petro@petrosalema.com					 *
 *											 *
\* * * * * * * * * * * * * * * * * * * * * * */

var Ajax = {
	
	/*
	connections: [
		(priority)	(priority)
			1	=	[ hxr, xhr ],
			2	=	[ xhr ],
			3	=	[ xhr, xhr, xhr ],
			4	=	[ xhr ]
		]
	*/
	connections: [],
	RETRY_DELAY: 1000,
	state:		 'ready',
	
	dispatch: function ( requestId )
	{
		var r		 = Ajax.getXhr( requestId ).request,
			call	 = r.url,
			t		 = r.transport,
			method	 = r.method,
			postdata = r.postdata,
			i		 = 0,
			poststring;
		
		/* If the request is on "busy", then try again in 1 second */
		if ( r.busy )
		{/*
			setTimeout(
					Ajax.dispatch.bind( {}, requestId ), Ajax.RETRY_DELAY
				);
			return;
		*/}
		
		if ( r.fresh )
			call += ( ( r.url.indexOf( '?' ) > -1 ) ? '&' : '?' )
				 + 'rand=' + Math.random();
		
		try
		{
			t.open( method, call, true );
			
			poststring = '';
			
			if ( postdata )
			{
				t.setRequestHeader(
						'Content-Type',
						'application/x-www-form-urlencoded; charset=UTF-8'
					);
				for ( ; i < postdata.length; i++ )
					poststring += '&' + postdata[i][0] + '='
							   + encodeURIComponent( postdata[i][1] );
			}
			
			t.send( poststring );
			
			this.state = 'busy';
			
			t.onreadystatechange = r.callback.bind( r );
			
			t.onabort = function ( requestId, method, postdata, poststring )
			{
				/* Try again ... */
				//Ajax.dispatch( requestId, method, postdata );
				//BAROOHA.modal( 'ABORTED', poststring );
			}.bind( {}, requestId, method, postdata, poststring );
		}
		catch( e )
		{
			r.failed( 'Could not send request' );
			return;
		}
		
		//r.busy = true;
	},
	
	getTransport: function ()
	{
		if ( window.XMLHttpRequest )
			return new XMLHttpRequest();
		else if ( window.ActiveXObject )
			return new ActiveXObject( 'Microsoft.XMLHTTP' );
		else
			return false;
	},
	
	getXhr: function ( requestId )
	{
		var c = Ajax.connections,
			i = 0,
			j;
		
		for ( ; i < c.length; i++ )
			if ( c[i] )
				for ( j = 0; j < c[i].length; j++ )
					if ( c[i][j].id == requestId )
						return c[i][j];
	},
	
	next: function ()
	{
		this.state = 'ready';
		
		var c = this.connections,
			i = 0;
		
		for ( ; i < c.length; i++ )
			if ( c[i] )
				if ( c[i].length )
				{
					this.dispatch( c[i][0].id );
					
					return;
				}
	},
	
	/**
	 * Removes the Ajax request from the lists of connections
	 */
	removeXhr: function ( requestId )
	{
		var c = Ajax.connections,
			i = 0,
			j,
			r;
		
		for ( ; i < c.length; i++ )
			if ( c[i] )
				for ( j = 0; j < c[i].length; j++ )
				{
					r = c[i][j];
					
					if ( r.id == requestId )
					{
						clearTimeout( r.timer );
						
						r.timer		= null;
						r.transport	= null;
						r.request	= null;
						
						c[i].splice( j, 1 );
					}
					
					if ( !c[i].length )
						delete c[i];
					
					return;
				}
	}
	
};

Ajax.Request = Class({
	
	/* * * * * * * * * * Ajax.Request Class * * * * * * * * * */
	
	transporter: null,
	busy:		 false,
	url:		 null,
	oncomplete:	 null,
	canvas:		 null,
	fresh:		 false,
	interval:	 false,
	timer:		 null,
	transport:	 null,
	method:		 null,
	postdata:	 null,
	priority:	 2,
	
	_initialize: function ( url, postdata, oncomplete, fresh, interval,
							priority )
	{
		this.id = ( '' + ( ( new Date() ).getTime() * Math.random() ) )
					.replace( /\./g, '_' );
		this.url		= url;
		this.oncomplete	= oncomplete;
		this.fresh		= fresh	   || false;
		this.interval	= false, //interval || false;
		this.transport	= Ajax.getTransport();
		this.method		= postdata ? 'POST' : 'GET';
		this.postdata	= postdata;
		this.priority	= priority || 2;
		
		if ( this.transport )
		{
			if ( !Ajax.connections[ this.priority ] )
				Ajax.connections[ this.priority ] = [];
			
			Ajax.connections[ this.priority ].push(
					{ id: this.id, request: this }
				);
			
			/* Check if the engine is busy with an item */
			if ( Ajax.state != 'busy' )
				Ajax.dispatch( this.id );
		}
		else
			this.failed( 'Could not create HTTPRequest object' );
	},
	
	callback: function ()
	{
		var t = this.transport;
		
		if ( t.readyState == 4 )
		{
			try
			{
				if ( t.status == 200 )
					this.succeeded();
				else
					this.failed( t.status + ' error!' );
			}
			catch( e )
			{
				this.failed( 'Firefox error: ' + e );
			}
			
			Ajax.next();
		}
	},
	
	failed: function ( msg )
	{
		if ( !/Firefox error/.test( msg ) )
			; //this.modal( 'Request Error', msg );
		
		this.transport.abort();
		
		Ajax.removeXhr( this.id );
	},
	
	succeeded: function ()
	{
		if ( this.oncomplete )
			this.oncomplete( this.transport.responseText );
		
		/* If it's a periodical request, then repeat it after interval
		milliseconds */
		if ( this.interval )
		{
			this.busy = false;
			this.timer = setTimeout(
					Ajax.dispatch.bind( {}, this.id ), this.interval
				);
		}
		else
			Ajax.removeXhr( this.id );
	}
	
}); /* * * * * * * * * * / Ajax.Request Class * * * * * * * * * */


/**
                          )/_
                _.--..---"-,--c_
           \L..' Petrofied ._O__)_ For the eternal glory of Jesus!
   ,-.     _.+  _  \..--( /
     `\.-''__.-' \ (     \_
       `'''       `\__   /\
                   ')
    
*/

// IE5.5+ PNG Alpha Fix v2.0 Alpha: Background Tiling Support
// (c) 2008-2009 Angus Turnbull http://www.twinhelix.com

// This is licensed under the GNU LGPL, version 2.1 or later.
// For details, see: http://creativecommons.org/licenses/LGPL/2.1/

var IEPNGFix = window.IEPNGFix || {};

IEPNGFix.tileBG = function( elm, pngSrc, ready )
{
	// Params: A reference to a DOM element, the PNG src file pathname, and a
	// hidden "ready-to-run" passed when called back after image preloading.
	
	var data = this.data[ elm.uniqueID ],
		elmW = Math.max( elm.clientWidth, elm.scrollWidth ),
		elmH = Math.max( elm.clientHeight, elm.scrollHeight ),
		bgX = elm.currentStyle.backgroundPositionX,
		bgY = elm.currentStyle.backgroundPositionY,
		bgR = elm.currentStyle.backgroundRepeat;
	
	// Cache of DIVs created per element, and image preloader/data.
	if ( !data.tiles )
		data.tiles = {
				elm: elm,
				src: '',
				cache: [],
				img: new Image(),
				old: {}
			};
	
	var tiles = data.tiles,
		pngW = tiles.img.width,
		pngH = tiles.img.height;
	
	if ( pngSrc )
	{
		if ( !ready && pngSrc != tiles.src )
		{
			// New image? Preload it with a callback to detect dimensions.
			tiles.img.onload = function()
			{
				this.onload = null;
				IEPNGFix.tileBG( elm, pngSrc, 1 );
			};
			return tiles.img.src = pngSrc;
		}
	}
	else
	{
		// No image?
		if ( tiles.src ) ready = 1;
		pngW = pngH = 0;
	}
	
	tiles.src = pngSrc;
	
	if ( !ready && elmW == tiles.old.w && elmH == tiles.old.h &&
		 bgX == tiles.old.x && bgY == tiles.old.y && bgR == tiles.old.r )
		return;
	
	// Convert English and percentage positions to pixels.
	var pos = {
			top: '0%',
			left: '0%',
			center: '50%',
			bottom: '100%',
			right: '100%'
		},
		x,
		y,
		pc;
	
	x = pos[ bgX ] || bgX;
	y = pos[ bgY ] || bgY;
	
	if ( pc = x.match( /(\d+)%/ ) )
		x = Math.round( ( elmW - pngW ) * ( parseInt( pc[1] ) / 100 ) );
	
	if ( pc = y.match( /(\d+)%/ ) )
		y = Math.round( ( elmH - pngH ) * ( parseInt( pc[1] ) / 100 ) );
	
	x = parseInt( x );
	y = parseInt( y );
	
	// Handle backgroundRepeat.
	var repeatX = { "repeat": 1, "repeat-x": 1 }[ bgR ],
		repeatY = { "repeat": 1, "repeat-y": 1 }[ bgR ];
	
	if ( repeatX )
	{
		x %= pngW;
		if ( x > 0 ) x -= pngW;
	}
	
	if ( repeatY )
	{
		y %= pngH;
		if ( y > 0 ) y -= pngH;
	}
	
	// Go!
	this.hook.enabled = 0;
	if ( !( { relative: 1, absolute: 1 }[ elm.currentStyle.position ] ) )
		elm.style.position = 'relative';
	
	var count = 0,
		xPos,
		maxX = repeatX ? elmW : x + 0.1,
		yPos,
		maxY = repeatY ? elmH : y + 0.1,
		d,
		s,
		isNew;
	
	if ( pngW && pngH )
	{
		for ( xPos = x; xPos < maxX; xPos += pngW )
		{
			for ( yPos = y; yPos < maxY; yPos += pngH )
			{
				isNew = 0;
				
				if ( !tiles.cache[ count ] )
				{
					tiles.cache[ count ] = document.createElement( 'div' );
					isNew = 1;
				}
				
				var clipR = Math.max( 0, xPos + pngW > elmW ? elmW - xPos : pngW ),
					clipB = Math.max( 0, yPos + pngH > elmH ? elmH - yPos : pngH );
				
				d = tiles.cache[ count ];
				s = d.style;
				s.behavior = 'none';
				s.left = ( xPos - parseInt( elm.currentStyle.paddingLeft ) ) + 'px';
				s.top = yPos + 'px';
				s.width = clipR + 'px';
				s.height = clipB + 'px';
				s.clip = 'rect(' +
					( yPos < 0 ? 0 - yPos : 0 ) + 'px,' +
					clipR + 'px,' +
					clipB + 'px,' +
					( xPos < 0 ? 0 - xPos : 0 ) + 'px)';
				s.display = 'block';
				
				if ( isNew )
				{
					s.position = 'absolute';
					s.zIndex = -999;
					if ( elm.firstChild )
						elm.insertBefore( d, elm.firstChild );
					else
						elm.appendChild( d );
				}
				
				this.fix( d, pngSrc, 0 );
				
				count++;
			}
		}
	}
	
	while ( count < tiles.cache.length )
	{
		this.fix( tiles.cache[ count ], '', 0 );
		tiles.cache[ count++ ].style.display = 'none';
	}
	
	this.hook.enabled = 1;
	
	// Cache so updates are infrequent.
	tiles.old = {
			w: elmW,
			h: elmH,
			x: bgX,
			y: bgY,
			r: bgR
		};
};


IEPNGFix.update = function()
{
	var i, t;
	// Update all PNG backgrounds.
	for ( i in IEPNGFix.data )
	{
		t = IEPNGFix.data[i].tiles;
		if ( t && t.elm && t.src )
			IEPNGFix.tileBG( t.elm, t.src );
	}
};

IEPNGFix.update.timer = 0;

if ( window.attachEvent && !window.opera )
{
	window.attachEvent( 'onresize', function () {
		clearTimeout( IEPNGFix.update.timer );
		IEPNGFix.update.timer = setTimeout( IEPNGFix.update, 100 );
	} );
}

