/**
 * Utility jQuery Plugins
 *   Most of these are small utility functions/suites, and being so small, we copy the uncompressed source in
 *   The exception to this is the url parser function, which might be big enough to belong with the widgets.
 *
 * TOC:
 *   (General Programming)
 *     iff
 *     others      - inverts current selection, can also be used as an else for iff
 *     tap         - insert an arbitrary function into a jquery chain
 *     once        - execute an arbitrary function only one time (globally)
 *     type        - guesstimates datatype, jquery 1.8 should have this functionality builtin
 *     timers:     - wrapper for setTimeout, setInterval, etc
 *       everyTime
 *       oneTime
 *       stopTime
 *     uniq
 *     url parser
 *     postMessage
 *
 *   (Attributes)
 *     id
 *     batch:
 *       attrs, styles, offsets, widths, heights, htmls, texts, val, ids
 *     metadata
 *     caret       - gets or sets input caret within a text input or textarea
 *
 *   (Selectors)
 *     getUniqueSelector
 *     :startOfLine
 *     :endOfLine
 *     Viewport Selectors
 *     Bound Events
 *
 *   (DOM)
 *     unwrap
 *
 *   (AJAX)
 *     JSONP
 * 
 *   strftime
 *   konami code
 *   
 *   blockUI
 */

/**
 *  Workaround for broken $.fn.switchClass
 *  official version of this function uses the morphing function, and breaks in IE8
 */
(function($) {
  $.fn.switchClass = function(oldClass, newClass) {
    return this.removeClass(oldClass).addClass(newClass);
  };
})(jQuery);

/**
 * iff - v0.2 - 6/3/2009
 * http://benalman.com/projects/jquery-iff-plugin/
 *
 * Copyright (c) 2009 "Cowboy" Ben Alman
 * Licensed under the MIT license
 * http://benalman.com/about/license/
 */
(function($){
  '$:nomunge'; // Used by YUI compressor.

  $.fn.iff = function( test ) {
    var elems = !test || $.isFunction( test )
      && !test.apply( this, Array.prototype.slice.call(arguments, 1) )
      ? []
      : this;
    return this.pushStack( elems, 'iff', test );
  };

})(jQuery);

/**
 * Others
 */
jQuery.fn.others=function(){
	return this.end().not(this);
};

/**
 * ©2009 Jiayong Ou
 *
 * License (MIT):
 * http://github.com/jou/jquery.tap.js/blob/master/LICENSE
 */
(function(){
  jQuery.fn.tap = function(fn /* [callback_arg], [callback_arg], [...] */) {
    var args = jQuery.makeArray(arguments);
    args.unshift();

    fn.apply(this, args);
    return this;
  };
}());

/**
 * Filters elements that have not yet been processed.
 *
 * @param id
 *   If this is a string, it will be used in the class name applied to
 *   the elements for determining whether it has already been processed.
 *   The elements will get a class in the form of id-processed.
 *   Otherwise, this acts as a unique identifier; the id will be a generated
 *   number. If it's a function, it will additionally be called for each
 *   element using .each().
 * @param fn
 *   (Optional) If given, this function will be called for each element that
 *   has not yet been processed. The function should not return a value.
 *
 * @version 1.1
 * @see http://plugins.jquery.com/project/once
 *
 * Copyright (c) 2009 Konstantin Kaefer <mail@kkaefer.com>
 * Dual licensed under the MIT and GPL licenses.
 */
(function(c){var a={},b=0;c.fn.once=function(g,e){if(typeof g!="string"){if(!(g in a)){a[g]=++b}if(!e){e=g}g="jquery-once-"+a[g]}var d=g+"-processed",f=this.not("."+d).addClass(d);return c.isFunction(e)?f.each(e):f}})(jQuery);

/**
 * Type
 */
jQuery.extend(jQuery, {
	type: function(_l,_c) {
		var _n=1;
		if (_c&&_c.charAt(0)=='!') {
			_n=-1;
			_c=_c.substr(1);
		}
		switch(typeof _l) {
			case 'function': return _c?_c.indexOf('f')*_n>=0:'function';
			case 'number': return _c?_c.indexOf('n')*_n>=0:'number';
			case 'string': return _c?_c.indexOf('s')*_n>=0:'string';
			case 'undefined': return _c?_c.indexOf('u')*_n>=0:'';
			case 'object':
				if (_l instanceof Array) return _c?_c.indexOf('a')*_n>=0:'array';
				if (_l instanceof Boolean) return _c?_c.indexOf('b')*_n>=0:'boolean';
				if (_l instanceof Date) return _c?_c.indexOf('d')*_n>=0:'date';
				if (_l instanceof Image) return _c?_c.indexOf('i')*_n>=0:'image';
				if (_l instanceof RegExp) return _c?_c.indexOf('r')*_n>=0:'regexp';
				if (typeof _c=='function') return _c?_l instanceof _c:_l.constructor;
				return _c?_c.indexOf('h')*_n>=0:'hash';
		}
	}
});

/**
 * jQuery.timers - Timer abstractions for jQuery
 * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)
 * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).
 * Date: 2009/08/13
 *
 * @author Blair Mitchelmore
 * @version 1.1.3
 *
 **/

jQuery.fn.extend({
	everyTime: function(interval, label, fn, times, belay) {
		return this.each(function() {
			jQuery.timer.add(this, interval, label, fn, times, belay);
		});
	},
	oneTime: function(interval, label, fn) {
		return this.each(function() {
			jQuery.timer.add(this, interval, label, fn, 1);
		});
	},
	stopTime: function(label, fn) {
		return this.each(function() {
			jQuery.timer.remove(this, label, fn);
		});
	}
});

jQuery.extend({
	timer: {
		global: [],
		guid: 1,
		dataKey: "jQuery.timer",
		regex: /^([0-9]+(?:\.[0-9]*)?)\s*(.*s)?$/,
		powers: {
			// Yeah this is major overkill...
			'ms': 1,
			'cs': 10,
			'ds': 100,
			's': 1000,
			'das': 10000,
			'hs': 100000,
			'ks': 1000000
		},
		timeParse: function(value) {
			if (value == undefined || value == null)
				return null;
			var result = this.regex.exec(jQuery.trim(value.toString()));
			if (result[2]) {
				var num = parseFloat(result[1]);
				var mult = this.powers[result[2]] || 1;
				return num * mult;
			} else {
				return value;
			}
		},
		add: function(element, interval, label, fn, times, belay) {
			var counter = 0;

			if (jQuery.isFunction(label)) {
				if (!times)
					times = fn;
				fn = label;
				label = interval;
			}

			interval = jQuery.timer.timeParse(interval);

			if (typeof interval != 'number' || isNaN(interval) || interval <= 0)
				return;

			if (times && times.constructor != Number) {
				belay = !!times;
				times = 0;
			}

			times = times || 0;
			belay = belay || false;

			var timers = jQuery.data(element, this.dataKey) || jQuery.data(element, this.dataKey, {});

			if (!timers[label])
				timers[label] = {};

			fn.timerID = fn.timerID || this.guid++;

			var handler = function() {
				if (belay && this.inProgress)
					return;
				this.inProgress = true;
				if ((++counter > times && times !== 0) || fn.call(element, counter) === false)
					jQuery.timer.remove(element, label, fn);
				this.inProgress = false;
			};

			handler.timerID = fn.timerID;

			if (!timers[label][fn.timerID])
				timers[label][fn.timerID] = window.setInterval(handler,interval);

			this.global.push( element );

		},
		remove: function(element, label, fn) {
			var timers = jQuery.data(element, this.dataKey), ret;

			if ( timers ) {

				if (!label) {
					for ( label in timers )
						this.remove(element, label, fn);
				} else if ( timers[label] ) {
					if ( fn ) {
						if ( fn.timerID ) {
							window.clearInterval(timers[label][fn.timerID]);
							delete timers[label][fn.timerID];
						}
					} else {
						for ( fn in timers[label] ) {
							window.clearInterval(timers[label][fn]);
							delete timers[label][fn];
						}
					}

					for ( ret in timers[label] ) break;
					if ( !ret ) {
						ret = null;
						delete timers[label];
					}
				}

				for ( ret in timers ) break;
				if ( !ret )
					jQuery.removeData(element, this.dataKey);
			}
		}
	}
});

jQuery(window).bind("unload", function() {
	jQuery.each(jQuery.timer.global, function(index, item) {
		jQuery.timer.remove(item);
	});
});

/**
 *  Uniq Plugin
 */
(function($) {
  $.uniq = function(notUniqArray) {
    // Check that we were given an array
    // If not, return the object
    if (!$.isArray(notUniqArray)) return notUniqArray;

    // Add each array value as a key in a map
    var map = {};
    for (var index in notUniqArray) {
      value = notUniqArray[index];
      // Store type_value as a map key,
      // unless 5 and '5' would be the same as a map key
      map[typeof value + '_' + value] = value;
    }

    // Build a new array with each map keys
    var uniqValues = [];
    for (var key in map) {
      uniqValues.push(map[key]);
    }

    return uniqValues;
  };
})(jQuery);

/* ===========================================================================
 *
 * JQuery URL Parser
 * Version 1.0
 * Parses URLs and provides easy access to information within them.
 *
 * Author: Mark Perkins
 * Author email: mark@allmarkedup.com
 *
 * For full documentation and more go to http://projects.allmarkedup.com/jquery_url_parser/
 *
 * ---------------------------------------------------------------------------
 *
 * CREDITS:
 *
 * Parser based on the Regex-based URI parser by Steven Levithan.
 * For more information (including a detailed explaination of the differences
 * between the 'loose' and 'strict' pasing modes) visit http://blog.stevenlevithan.com/archives/parseuri
 *
 * ---------------------------------------------------------------------------
 *
 * LICENCE:
 *
 * Released under a MIT Licence. See licence.txt that should have been supplied with this file,
 * or visit http://projects.allmarkedup.com/jquery_url_parser/licence.txt
 *
 * ---------------------------------------------------------------------------
 *
 * EXAMPLES OF USE:
 *
 * Get the domain name (host) from the current page URL
 * jQuery.url.attr("host")
 *
 * Get the query string value for 'item' for the current page
 * jQuery.url.param("item") // null if it doesn't exist
 *
 * Get the second segment of the URI of the current page
 * jQuery.url.segment(2) // null if it doesn't exist
 *
 * Get the protocol of a manually passed in URL
 * jQuery.url.setUrl("http://allmarkedup.com/").attr("protocol") // returns 'http'
 *
 */
jQuery.url=function(){var e={};var b={};var d={url:window.location,strictMode:false,key:["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],q:{name:"queryKey",parser:/(?:^|&)([^&=]*)=?([^&]*)/g},parser:{strict:/^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,loose:/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/}};var c=function(){str=decodeURI(d.url);var j=d.parser[d.strictMode?"strict":"loose"].exec(str);var l={};var k=14;while(k--){l[d.key[k]]=j[k]||""}l[d.q.name]={};l[d.key[12]].replace(d.q.parser,function(m,i,n){if(i){l[d.q.name][i]=n}});return l};var f=function(i){if(!b.length){a()}if(i=="base"){if(b.port!==null&&b.port!==""){return b.protocol+"://"+b.host+":"+b.port+"/"}else{return b.protocol+"://"+b.host+"/"}}return(b[i]==="")?null:b[i]};var h=function(i){if(!b.length){a()}return(b.queryKey[i]===null)?null:b.queryKey[i]};var a=function(){b=c();g()};var g=function(){var i=b.path;e=[];e=b.path.length==1?{}:(i.charAt(i.length-1)=="/"?i.substring(1,i.length-1):path=i.substring(1)).split("/")};return{setMode:function(i){strictMode=i=="strict"?true:false;return this},setUrl:function(i){d.url=i===undefined?window.location:i;a();return this},segment:function(i){if(!b.length){a()}if(i===undefined){return e.length}return(e[i]===""||e[i]===undefined)?null:e[i]},attr:f,param:h}}();

/*!
 * postMessage - v0.5 - 9/11/2009
 * http://benalman.com/
 *
 * Copyright (c) 2009 "Cowboy" Ben Alman
 * Licensed under the MIT license
 * http://benalman.com/about/license/
 */

// Script: postMessage
//
// Version: 0.5, Date: 9/11/2009
//
// Tested with jQuery 1.3.2 in Internet Explorer 6-8, Firefox 3, Safari 3-4,
// Chrome, Opera 9.
//
// Home       - http://benalman.com/projects/jquery-postmessage-plugin/
// Source     - http://benalman.com/code/javascript/jquery/jquery.ba-postmessage.js
// (Minified) - http://benalman.com/code/javascript/jquery/jquery.ba-postmessage.min.js (0.9kb)
// Example    - http://benalman.com/code/test/js-jquery-postmessage/
//
//
// About: License
//
// Copyright (c) 2009 "Cowboy" Ben Alman
//
// Licensed under the MIT license
//
// http://benalman.com/about/license/
//
// Topic: What this plugin does
//
// With the addition of the window.postMessage method, JavaScript finally has a
// fantastic means for cross-domain frame communication. Unfortunately, this
// method isn't supported in all browsers. This jQuery plugin enables simple and
// easy window.postMessage communication in browsers that support it (FF3,
// Safari 4, IE8), while falling back to a document.location.hash communication
// method for all other browsers (IE6, IE7, Opera). One example where this is
// useful is when a child Iframe needs to tell its parent that its contents have
// resized.
//
// About: Revision History
//
// 0.5 - Improved cache busting
// 0.4 - Initial release

(function($){
  '$:nomunge'; // Used by YUI compressor.

  // A few vars used in non-awesome browsers.
  var interval_id,
    last_hash,
    cache_bust = 1,

    // A var used in awesome browsers.
    rm_callback,

    // A few convenient shortcuts.
    window = this,
    FALSE = !1,

    // Reused internal strings.
    postMessage = 'postMessage',
    addEventListener = 'addEventListener',

    p_receiveMessage,

    // I couldn't get window.postMessage to actually work in Opera 9.64!
    has_postMessage = window[postMessage] && !$.browser.opera;

  // Method: jQuery.postMessage
  //
  // This method will call window.postMessage if available, setting the
  // targetOrigin parameter to the base of the target_url parameter for maximum
  // security in browsers that support it. If window.postMessage is not available,
  // the target window's location.hash will be used to pass the message. If an
  // object is passed as the message param, it will be serialized into a string
  // using the jQuery.param method.
  //
  // Usage:
  //
  //  jQuery.postMessage( message, target_url [, target ] );               - -
  //
  // Arguments:
  //
  //  message - (String or Object) The window.postMessage method only supports a
  //    string message, but if an object is passed it will be serialized using
  //    the jQuery.param method.
  //  target_url - (String) The URL of the other frame this window is
  //    attempting to communicate with. This must be the exact URL (including
  //    query string) of the other window for this script to work in browsers
  //    that don't support window.postMessage.
  //  target - (Object) A reference to the other frame this window is
  //    attempting to communicate with. If unspecified, defaults to parent.
  //
  // Returns:
  //
  //  Nothing.

  $[postMessage] = function( message, target_url, target ) {
    if ( !target_url ) { return; }

    // Serialize the message if not a string. Note that this is the only real
    // jQuery dependency for this script. If removed, this script could be
    // written as very basic JavaScript.
    message = typeof message === 'string' ? message : $.param( message );

    // Default to parent if unspecified.
    target = target || parent;

    if ( has_postMessage ) {
      // The browser supports window.postMessage, so call it with a targetOrigin
      // set appropriately, based on the target_url parameter.
      target[postMessage]( message, target_url.replace( /([^:]+:\/\/[^\/]+).*/, '$1' ) );

    } else if ( target_url ) {
      // The browser does not support window.postMessage, so set the location
      // of the target to target_url#message. A bit ugly, but it works! A cache
      // bust parameter is added to ensure that repeat messages trigger the
      // callback.
      target.location = target_url.replace( /#.*$/, '' ) + '#' + (+new Date) + (cache_bust++) + '&' + message;
    }
  };

  // Method: jQuery.receiveMessage
  //
  // Register a single callback for either a window.postMessage call, if
  // supported, or if unsupported, for any change in the current window
  // location.hash. If window.postMessage is supported and source_origin is
  // specified, the source window will be checked against this for maximum
  // security. If window.postMessage is unsupported, a polling loop will be
  // started to watch for changes to the location.hash.
  //
  // Note that for simplicity's sake, only a single callback can be registered
  // at one time. Passing no params will unbind this event (or stop the polling
  // loop), and calling this method a second time with another callback will
  // unbind the event (or stop the polling loop) first, before binding the new
  // callback.
  //
  // Usage:
  //
  //  jQuery.receiveMessage( callback [, source_origin ] [, delay ] );       - -
  //
  // Arguments:
  //
  //  callback - (Function) This callback will execute whenever a <jQuery.postMessage>
  //    message is received, provided the source_origin matches. If callback is
  //    omitted, any existing event bind or polling loop will be canceled.
  //  source_origin - (String or Function) If window.postMessage is available,
  //    this optional param will be used to test the event.origin property. If
  //    the param is a string, and is not equal to the event.origin property, or
  //    a function that returns false when passed the event.origin property, the
  //    callback will not be called. From the MDC window.postMessage docs:
  //    This string is the concatenation of the protocol and "://", the host
  //    name if one exists, and ":" followed by a port number if a port is
  //    present and differs from the default port for the given protocol.
  //    Examples of typical origins are https://example.org (implying port 443),
  //    http://example.net (implying port 80), and http://example.com:8080.
  //  delay - (Number) An optional zero-or-greater delay in milliseconds at
  //    which the polling loop will execute (for browser that don't support
  //    window.postMessage). If unspecified, defaults to 100.
  //
  // Returns:
  //
  //  Nothing!

  $.receiveMessage = p_receiveMessage = function( callback, source_origin, delay ) {
    if ( has_postMessage ) {
      // Since the browser supports window.postMessage, the callback will be
      // bound to the actual event associated with window.postMessage.

      if ( callback ) {
        // Unbind an existing callback if it exists.
        rm_callback && p_receiveMessage();

        // Bind the callback. A reference to the callback is stored for ease of
        // unbinding.
        rm_callback = function(e) {
          if ( ( typeof source_origin === 'string' && e.origin !== source_origin )
            || ( $.isFunction( source_origin ) && source_origin( e.origin ) === FALSE ) ) {
            return FALSE;
          }
          callback( e );
        };
      }

      if ( window[addEventListener] ) {
        window[ callback ? addEventListener : 'removeEventListener' ]( 'message', rm_callback, FALSE );
      } else {
        window[ callback ? 'attachEvent' : 'detachEvent' ]( 'onmessage', rm_callback );
      }

    } else {
      // Since the browser sucks, a polling loop will be started, and the
      // callback will be called whenever the location.hash changes.

      interval_id && clearInterval( interval_id );
      interval_id = null;

      if ( callback ) {
        delay = typeof source_origin === 'number'
          ? source_origin
          : typeof delay === 'number'
            ? delay
            : 100;

        interval_id = setInterval(function(){
          var hash = document.location.hash,
            re = /^#?\d+&/;
          if ( hash !== last_hash && re.test( hash ) ) {
            last_hash = hash;
            callback({ data: hash.replace( re, '' ) });
          }
        }, delay );
      }
    }
  };

})(jQuery);

/**
 * Logger
 */
(function($) {
  $.log = function() {
    appendLogEntry(log_queue, arguments);
    if ($.log.settings.logToConsole) {
      try { browser_logger.apply(null, arguments); } catch(_) {}
    }
    return $.log;
  };

  $.log.log = $.log; // for chained logs $.log().log(), rather than $.log()()

  $.log.report = function(mode) {
    report(log_queue, mode);
  };

  $.log.trace = function() {
    browser_trace();
    return $.log;
  };

  $.log.profile = function() {
    if (window.console) {
      if (!arguments.length || "start" == arguments[0]) {
        try { console.profile(); } catch(_) {}
      } else if ("stop" == arguments[0]) {
        try { console.profileEnd(); } catch(_) {}
      }
    }
    return $.log;
  };

  $.fn.log = function() {
    var domLog = $(this).data("log_queue");
    if (!domLog) {
      domLog = [];
      $(this).data("log_queue", domLog);
    }
    appendLogEntry(domLog, arguments);
    $.log.apply(null, arguments);
    return this;
  };

  $.fn.logReport = function(mode) {
    report($(this).data("log_queue"), mode);
    return this;
  };

  var detectBrowserLoggingFunctions = function() {
    if (window.console) {
      browser_logger = console.log || console.debug || console.info || console.warn || console.error;
      if (console.trace) {
        browser_trace = console.trace;
      } else {
        // make our own
        // appendLogEntry(log_queue, ?);
      }
      return true;
    }
    return false;
  };

  var report = function(log, mode) {
    if (pollForConsole) {
      pollForConsole = !detectBrowserLoggingFunctions();
      if (pollForConsole) {
        return;
      }
    }

    if (mode && $.log.report.hasOwnProperty(mode) && $.isFunction($.log.report[mode])) {
      $.log.report[mode](log, browser_logger);
    } else {
      $.log.report.basic(log, browser_logger);
    }
  };

  var appendLogEntry = function(log, data) {
    log.push({ timestamp: (new Date()).getTime(), data: data });
    if (-1 == $.inArray(log, trim_queue)) {
      trim_queue.push(log);
    }
    if (!trim_timer) {
      trim_timer = setTimeout(trimQueues, $.log.settings.minEntryDuration);
    }
  };

  var trimQueues = function() {
    var maxTS = (new Date()).getTime() - $.log.settings.maxEntryDuration;
    var minTS = (new Date()).getTime() - $.log.settings.minEntryDuration;
    for (var i = 0; i < trim_queue.length; ++i) {
      var maxEntries = (trim_queue[i] == log_queue) ? $.log.settings.maxGlobalEntries : $.log.settings.maxDomEntries;
      for (var trimPoint1 = 0; trimPoint1 < trim_queue[i].length && trim_queue[i][trimPoint1].timestamp < maxTS; ++trimPoint1) {}
      for (var trimPoint = Math.max(trimPoint1 - 1, trim_queue[i].length - maxEntries); trimPoint > 0 && trim_queue[i][trimPoint].timestamp > minTS; --trimPoint){}
      if (trimPoint > 0) {
        //console.debug("trimming first %d log entries", trimPoint + 1);
        trim_queue[i].splice(0, trimPoint + 1);
      }
      if (!trim_queue[i].length) {
        trim_queue.splice(i, 1);
        --i;
      }
    }

    if (pollForConsole && window.console) {
      pollForConsole = !detectBrowserLoggingFunctions();
      if (!pollForConsole && $.log.settings.logToConsole) {
        report(log_queue);
      }
    }

    if (trim_queue.length) {
      trim_timer = setTimeout(trimQueues, $.log.settings.trimInterval);
    } else {
      trim_timer = null;
    }
  };

  var log_queue = [];
  var trim_queue = [];
  var trim_timer;
  var browser_logger = function(){};
  var browser_trace = function(){};
  var pollForConsole = !detectBrowserLoggingFunctions();

  $.log.report.basic = function(log, logger) {
    for (var i = 0; i < log.length; ++i) {
      logger.apply(null, $.makeArray(log[i].data));
    }
  };
  $.log.report.details = function(log, logger) {
    for (var i = 0; i < log.length; ++i) {
      logger.apply(null, [(new Date(log[i].timestamp)).toLocaleString(), ": "].concat($.makeArray(log[i].data)));
    }
  };
  /*$.log.report.hierarchy = function(log, logger) {
    if (log.length) {
      var createNode = function(entry, parent) {
        return { parent: parent, children: [entry], func: entry.data.callee, hasChildNodes: false };
      };
      var getCurNode = function(node, func) {
        var backFunc = func;
        while (backFunc) {
          if (backFunc = node.func) {
            return node;
          }
          backFunc = backFunc.caller;
        }
        if (node.parent) {
          return getCurNode(node.parent, func);
        }
        return node;
      };
      var top, cur;
      top = cur = { parent: null, children: [], func: null, hasChildNodes: false };
      for (var i = 0; i < log.length; ++i) {
        cur = getCurNode(cur, log[i].data.callee);
        if (cur.func == log[i].data.callee) {
          cur.children.push(log[i]);
        } else {
          var newNode = createNode(log[i], cur);
          cur.children.push(newNode);
          cur.hasChildNodes = true;
          cur = newNode;
        }
      }
      var print = function(node) {
        if (node.hasChildNodes) {
          (console.group || logger).call(null, "");
        }
        for (var i = 0; i < node.children.length; ++i) {
          if (node.children[i].children) {
            print(node.children[i]);
          } else {
            logger.apply(null, [].splice.call(node.children[i].data, 0));
          }
        }
        if (node.hasChildNodes) {
          try { console.groupEnd(); } catch(_) {}
        }
      };
      print(top);
    }
  };*/

  $.log.settings = {
    maxGlobalEntries: 1000,
    maxDomEntries: 50,
    maxEntryDuration: 3600000,
    minEntryDuration: 15000,
    trimInterval: 5000,
    logToConsole: false
  };
})(jQuery);

/**
 * ID Plugin
 */
(function($) {
  $.fn.id = function(newid) {
    if ("undefined" != typeof newid) {
      $(this).attr("id", newid);
    } else {
      return $(this).attr("id");
    }
  };
})(jQuery);

/** Copyright (c) 2007 Brandon Aaron (http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * $LastChangedDate: 2008-05-09 09:24:44 -0500 (Fri, 09 May 2008) $
 * $Rev: 5535 $
 *
 * Version: 1.0.1
 */
(function($){

$.fn.batch = function(method) {
	var args = $.makeArray(arguments).slice(1), results = [];
	this.each(function() {
		results.push( $(this)[method].apply($(this), args) );
	});
	return results;
};

$.batch = {
	version: "1.0.1",
	registerPlugin: function() {
		$.each( arguments, function( index, plugin ) {
			var method = plugin.constructor == Array && plugin[0] || plugin,
				newMethod = plugin.constructor == Array && plugin[1] || plugin+"s";
			if ( $.fn[ method ] && !$.fn[ newMethod ] )
				$.fn[ newMethod ] = function() {
					return this.batch.apply( this, [ method ].concat( $.makeArray(arguments) ) );
				};
		});
	}
};

$.batch.registerPlugin( 'attr', ['css','styles'], 'offset', 'width', 'height', 'html', 'text', 'val' );

// Gilt Modification:
$.batch.registerPlugin('id');

})(jQuery);

/*
 * Metadata - jQuery plugin for parsing metadata from elements
 *
 * Copyright (c) 2006 John Resig, Yehuda Katz, J?šrn Zaefferer, Paul McLanahan
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id: jquery.metadata.js 3640 2007-10-11 18:34:38Z pmclanahan $
 *
 * Sets the type of metadata to use. Metadata is encoded in JSON, and each property
 * in the JSON will become a property of the element itself.
 *
 * There are four supported types of metadata storage:
 *
 *   attr:  Inside an attribute. The name parameter indicates *which* attribute.
 *
 *   class: Inside the class attribute, wrapped in curly braces: { }
 *
 *   elem:  Inside a child element (e.g. a script tag). The
 *          name parameter indicates *which* element.
 *   html5: Values are stored in data-* attributes.
 *
 * The metadata for an element is loaded the first time the element is accessed via jQuery.
 *
 * As a result, you can define the metadata type, use $(expr) to load the metadata into the elements
 * matched by expr, then redefine the metadata type and run another $(expr) for other elements.
 *
 * @name $.metadata.setType
 *
 * @example <p id="one" class="some_class {item_id: 1, item_label: 'Label'}">This is a p</p>
 * @before $.metadata.setType("class")
 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
 * @desc Reads metadata from the class attribute
 *
 * @example <p id="one" class="some_class" data="{item_id: 1, item_label: 'Label'}">This is a p</p>
 * @before $.metadata.setType("attr", "data")
 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
 * @desc Reads metadata from a "data" attribute
 *
 * @example <p id="one" class="some_class"><script>{item_id: 1, item_label: 'Label'}</script>This is a p</p>
 * @before $.metadata.setType("elem", "script")
 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
 * @desc Reads metadata from a nested script element
 *
 * @example <p id="one" class="some_class" data-item_id="1" data-item_label="Label">This is a p</p>
 * @before $.metadata.setType("html5")
 * @after $("#one").metadata().item_id == 1; $("#one").metadata().item_label == "Label"
 * @desc Reads metadata from a series of data-* attributes
 *
 * @param String type The encoding type
 * @param String name The name of the attribute to be used to get metadata (optional)
 * @cat Plugins/Metadata
 * @descr Sets the type of encoding to be used when loading metadata for the first time
 * @type undefined
 * @see metadata()
 */

(function($) {

$.extend({
  metadata : {
    defaults : {
      type: 'class',
      name: 'metadata',
      cre: /({.*})/,
      single: 'metadata'
    },
    setType: function( type, name ){
      this.defaults.type = type;
      this.defaults.name = name;
    },
    get: function( elem, opts ){
      var settings = $.extend({},this.defaults,opts);
      // check for empty string in single property
      if ( !settings.single.length ) settings.single = 'metadata';

      var data = $.data(elem, settings.single);
      // returned cached data if it already exists
      if ( data ) return data;

      data = "{}";

      var getData = function(data) {
        if(typeof data != "string") return data;

        if( data.indexOf('{') < 0 ) {
          data = eval("(" + data + ")");
        }
      };

      var getObject = function(data) {
        if(typeof data != "string") return data;

        data = eval("(" + data + ")");
        return data;
      };

      if ( settings.type == "html5" ) {
        var object = {};
        $( elem.attributes ).each(function() {
          var name = this.nodeName;
          if(name.match(/^data-/)) name = name.replace(/^data-/, '');
          else return true;
          object[name] = getObject(this.nodeValue);
        });
      } else {
        if ( settings.type == "class" ) {
          var m = settings.cre.exec( elem.className );
          if ( m )
            data = m[1];
        } else if ( settings.type == "elem" ) {
          if( !elem.getElementsByTagName ) return;
          var e = elem.getElementsByTagName(settings.name);
          if ( e.length )
            data = $.trim(e[0].innerHTML);
        } else if ( elem.getAttribute != undefined ) {
          var attr = elem.getAttribute( settings.name );
          if ( attr )
            data = attr;
        }
        object = getObject(data.indexOf("{") < 0 ? "{" + data + "}" : data);
      }

      $.data( elem, settings.single, object );
      return object;
    }
  }
});

/**
 * Returns the metadata object for the first member of the jQuery object.
 *
 * @name metadata
 * @descr Returns element's metadata object
 * @param Object opts An object contianing settings to override the defaults
 * @type jQuery
 * @cat Plugins/Metadata
 */
$.fn.metadata = function( opts ){
  return $.metadata.get( this[0], opts );
};

})(jQuery);

/**
 * Caret Plugin
 */
(function($) {
  $.fn.caret = function(pos) {
    var target = this[0];
    if (arguments.length == 0) { //get
      if (target.selectionStart) { //DOM
        pos = target.selectionStart;
        return pos > 0 ? pos : 0;
      }
      else if (target.createTextRange) { //IE
        target.focus();
        var range = document.selection.createRange();
        if (range == null)
          return '0';
        var re = target.createTextRange();
        var rc = re.duplicate();
        re.moveToBookmark(range.getBookmark());
        rc.setEndPoint('EndToStart', re);
        return rc.text.length;
      }
      else return 0;
    } //set
    if (target.setSelectionRange) //DOM
      target.setSelectionRange(pos, pos);
    else if (target.createTextRange) { //IE
      range = target.createTextRange();
      range.collapse(true);
      range.moveEnd('character', pos);
      range.moveStart('character', pos);
      range.select();
    }
  };
})(jQuery);

/**
 * Unique Selector
 *
 * @version 0.5
 * @requires jQuery v1.3
 * @author Kevan Davis
 * @copyright Copyright (c) 2009, Gilt Groupe
 *
 * Distributed under the terms of the GNU General Public License
 * http://www.gnu.org/licenses/gpl-3.0.html
 *
 * Calculates a unique css selector for an element
 *
 * Attempts have been made to optimize the selector, but it's far from perfect
 */
(function($) {
  var helper = function(el, first) {
    var path = "";
    if (el.attr("id")) {
      return "#" + el.attr ("id"); // If it has an id, no need for anything above this point, since ids are required to be unique
    } else {
      path = el[0].nodeName.toLowerCase(); // get the nodename, e.g. "div"
      if (el.attr("class")) {
        path += "." + el.attr("class").split(" ")[0]; // if it has a class, append it, e.g. "div.mydiv"
      }
      if (el.prevAll(path).length || el.nextAll(path).length) { // if there are multiple such elements at this level, append an index, e.g. "div.mydiv:eq(7)"
        path += ":eq(" + el.prevAll(path).length + ")";
      }
    }
    if (el.parent().length) { // in an (x)html document, should always return true, since we never reach the Document itself.  in XML, it will return false for the root element
      if (el.parent()[0] == $("body")[0]) {
        return "body " + path;
      } else if (el.parent()[0] == $("head")[0]) {
        return "head " + path;
      } else if (el.parent()[0] == $("html")[0]) {
        if (el[0].nodeName.toLowerCase() == "body") {
          return "body";
        } else if (el[0].nodeName.toLowerCase() == "head") {
          return "head";
        }
        return "html " + path;
      } else if (!first) { // ok, we're not at the top, and we're not at the bottom
        if (!el.siblings().length) { // if we're an only child, no need to be included
          return helper(el.parent(), false) + "!"; // appending a "!", we look for this afterwords, and remove it and any ">" that follows
        }
      }
      return helper(el.parent(), false) + ">" + path;
    }
    return path;
  };
  $.fn.getUniqueSelector = function() {
    return helper(this, true).replace(/!+>?/g, " ");
  };
})(jQuery);

/**
 * Start/End of Line Selectors
 *
 * @version 0.9
 * @requires jQuery v1.3
 * @author: Kevan Davis (kdavis@gilt.com)
 * @copyright Copyright (c) 2009, Gilt Groupe
 *
 * Distributed under the terms of the GNU General Public License
 * http://www.gnu.org/licenses/gpl-3.0.html
 *
 **/
(function($){
  $.extend($.fn, {
    startOfLine: function(strict) {
      var elements = this;
      var targets = [];
      var i = -1;
      var max = elements.length;

      while (++i < max) {
        var el = $(elements[i]);
        var el_top = el.offset().top - parseInt(el.css("margin-top"));
        var sibs = el.prevAll();
        var j = -1;
        var end = sibs.length;
        var target = el;
        var candidate;

        while (++j < end) {
          candidate = sibs.eq(j);
          var c_bottom = candidate.offset().top + candidate.height() + parseInt(candidate.css("margin-bottom"));
          if (el_top < c_bottom) {
            if (strict) {
              var c_top = candidate.offset().top - parseInt(candidate.css("margin-top"));
              if (c_top >= el_top) {
                target = candidate;
              }
            } else {
              target = candidate;
            }
          }
        }
        targets.push(target.get(0));
      }
      return $(targets);
    },
    endOfLine: function(strict, lazy) {
      var elements = this;
      var targets = [];
      var i = -1;
      var max = elements.length;

      while (++i < max) {
        var el = $(elements[i]);
        var el_bottom = el.offset().top + el.height() + parseInt(el.css("margin-bottom"));
        var sibs = el.nextAll();
        var j = sibs.length;
        var target = el;
        var candidate;

        while (j--) {
          candidate = sibs.eq(j);
          var c_top = candidate.offset().top - parseInt(candidate.css("margin-top"));
          if (c_top < el_bottom) {
            if (strict) {
              var c_bottom = candidate.offset().top + candidate.height() + parseInt(candidate.css("margin-bottom").replace(/px/i,''));
              if (c_bottom <= el_bottom) {
                target = candidate;
              }
            } else {
              target = candidate;
            }
          }
        }
        targets.push(target.get(0));
      }
      return $(targets);
    }
  });
})(jQuery);

/*
 * Viewport - jQuery selectors for finding elements in viewport
 *
 * Copyright (c) 2008-2009 Mika Tuupola
 * Copyright (c) 2009 Kevan Davis, Gilt Groupe
 *
 * Licensed under the MIT license:
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * Project home:
 *   http://www.appelsiini.net/projects/viewport
 *
 * Gilt Groupe Modification:
 *   Added :below(selector), :above(selector), :right-of(selector), :left-of(selector),
 *   :with-in(selector) selectors.  Behave same as existing selectors, but relative to
 *   the first element returned by a selector.  :with-in requires that part of the
 *   matched element be within the selected element.
 */
(function($) {
  $.belowthefold = function(element, settings) {
    return $.below(element, window, settings);
  };

  $.abovethetop = function(element, settings) {
    return $.above(element, window, settings);
  };

  $.rightofscreen = function(element, settings) {
    return $.rightof(element, window, settings);
  };

  $.leftofscreen = function(element, settings) {
    return $.leftof(element, window, settings);
  };

  $.inviewport = function(element, settings) {
    return $.within(element, window, settings);
  };

  $.below = function(element1, element2, settings) {
    var bottom = $(element2).height() + $(element2).scrollTop();
    return bottom <= $(element1).offset().top - settings.threshold;
  };

  $.above = function(element1, element2, settings) {
    var top = $(element2).scrollTop();
    return top >= $(element1).offset().top + $(element1).height() - settings.threshold;
  };

  $.rightof = function(element1, element2, settings) {
    var right = $(element2).width() + $(element2).scrollLeft();
    return right <= $(element1).offset().left - settings.threshold;
  };

  $.leftof = function(element1, element2, settings) {
    var left = $(element2).scrollLeft();
    return left >= $(element1).offset().left + $(element1).width() - settings.threshold;
  };

  $.within = function(element1, element2, settings) {
    return !$.rightof(element1, element2, settings) && !$.leftof(element1, element2, settings) && !$.below(element1, element2, settings) && !$.above(element1, element2, settings);
  };

  $.extend($.expr[':'], {
    "below-the-fold": function(a, i, m) {
      return $.below(a, window, {threshold : 0});
    },
    "above-the-top": function(a, i, m) {
      return $.above(a, window, {threshold : 0});
    },
    "left-of-screen": function(a, i, m) {
      return $.leftof(a, window, {threshold : 0});
    },
    "right-of-screen": function(a, i, m) {
      return $.rightof(a, window, {threshold : 0});
    },
    "in-viewport": function(a, i, m) {
      return $.inview(a, window, {threshold : 0});
    },
    "below": function(a, i, m) {
      return $.below(a, m, {threshold : 0});
    },
    "above": function(a, i, m) {
      return $.above(a, m, {threshold : 0});
    },
    "left-of": function(a, i, m) {
      return $.leftof(a, m, {threshold : 0});
    },
    "right-of": function(a, i, m) {
      return $.rightof(a, m, {threshold : 0});
    },
    "with-in": function(a, i, m) {
      return $.within(a, m, {threshold : 0});
    }
  });
})(jQuery);



/**
 * Bound Event(s) Plugin
 *
 * @version 0.9
 * @requires jQuery v1.3
 * @author Kevan Davis
 * @copyright Copyright (c) 2009, Gilt Groupe
 *
 * Distributed under the terms of the GNU General Public License
 * http://www.gnu.org/licenses/gpl-3.0.html
 *
 * @description :
 *
 * Returns an array of events bound to an element
 * If a type is passed in, returns only those types.
 *
 * CSS Pseudo Selector :bound(eventType) returns elements that have events of a certain type
 *
 * Also supports namespaced events
 *
 * @usage :
 * $('#blah').bound('click') -- returns all functions bound to the click event on #blah
 * $('#blah').bound() -- returns all functions bound to any event on #blah
 * $('.blah').bound('.test') -- returns all functions bound to the test namespace on the first element with class blah
 * $('.blah:bound(click.test)') -- returns all elements with class blah that have a click handler in namespace test
 */
(function($) {
  $.fn.bound = function(type) {
    var namespace = null;
    if (0 == type.indexOf(".")) {
      namespace = type.substr(1);
      type = null;
    } else if(-1 != type.indexOf(".")) {
      var p = type.split(".");
      namespace = p[1];
      type = p[0];
    }
    var events = $(this).data("events");
    if (!events) {
      return [];
    }
    if (type) {
      events = events[type]||{};
    } else {
      var old = events;
      events = {};
      for (var group in old) {
        if (old.hasOwnProperty(group)) {
          $.extend(events, old[group]);
        }
      }
    }
    var eventsArray = [];
    for (var e in events) {
      if (events.hasOwnProperty(e)) {
        if (!namespace || events[e].type == namespace) {
          eventsArray.push(events[e]);
        }
      }
    }
    return eventsArray;
  };
  $.extend($.expr[":"], {
    "bound": function(a, i, m) {
      var found = false;
      if (m && m[3]) {
        var events = m[3].split(",");
        var j = events.length;
        while (j--) {
          if ($(a).bound(events[j]).length) {
            found = true;
            break;
          }
        }
      } else {
        if ($(a).bound().length) {
          found = true;
        }
      }
      return found;
    }
  });
})(jQuery);

/*
	Unwrap extension for jQuery
	Version: 1.1

	Copyright (c) 2009 Todd Northrop
	http://www.speednet.biz/

	June 7, 2009

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version, subject to the following conditions:

	The above copyright notice and this permission notice shall be
	included in all copies or substantial portions of the Software.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
------------------------------------------------------*/

jQuery.fn.unwrap = function (selector) {
	///	<summary>
	///		Removes the immediate parent wrapping element from each element of the matched set.
	/// 	For elements in the matched set that share a common parent, the common parent element
	/// 	is removed.
	///	</summary>
	///	<returns type="jQuery">
	///		Returns the original jQuery matched set.
	/// </returns>
	/// <remarks>
	/// 	To keep things simple, I have avoided adding a selector argument to this extension.
	/// 	I suppose I could add it, but perhaps that is best done with a .filter() before
	/// 	calling .unwrap(). If you have an opinion about this, let me know.
	///
	/// 	New for version 1.1, elements in the wrapped set that are direct children of the
	/// 	body tag will not be unwrapped, because doing so would delete the body tag.
	/// </remarks>

	return this.parent(":not(body)").filter(selector || "*").each(
		function () {
			var $set = jQuery(this);
			$set.replaceWith($set.contents());
		}
	).end();
};

/*
 * JQuery strftime plugin
 * Version 1.0.1 (12/06/2008)
 *
 * No documentation at this point, sorry.
 *
 * Home page: http://projects.nocternity.net/jquery-strftime/
 * Examples: http://projects.nocternity.net/jquery-strftime/demo.html
 *
 * Copyright (c) 2008 Emmanuel Beno”t
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

$(function(){

 var _defaults = {
   'days_short' : [ 'Sun', 'Mon' , 'Tue' , 'Wed' , 'Thu' ,
       'Fri' , 'Sat' ] ,
   'days_long' : [ 'Sunday' , 'Monday' , 'Tuesday' ,
       'Wednesday' , 'Thursday' , 'Friday' ,
       'Saturday' ] ,
   'months_short' : [ 'Jan' , 'Feb' , 'Mar' , 'Apr' ,
       'May' , 'Jun' , 'Jul' , 'Aug' ,
       'Sep' , 'Oct' , 'Nov' , 'Dec' ] ,
   'months_long' : [ 'January' , 'February' , 'March' ,
       'April' , 'May' , 'June' , 'July' ,
       'August' , 'September' , 'October' ,
       'November' , 'December' ] ,
   'format' : '%m/%d/%Y'
 };

 var _useText = _defaults;

 var _finaliseObj = function ( _obj , _month , _dow ) {
   _obj.a = _useText.days_short[ _dow ];
   _obj.A = _useText.days_long[ _dow ];
   _obj.b = _useText.months_short[ _month ];
   _obj.B = _useText.months_long[ _month ];
   _obj.m = _month + 1;

   var _tmp;

   if ( _obj.Y > 0 ) {
     _tmp = _obj.Y.toString( );
     if ( _tmp.length < 2 ) {
       _tmp = '0' + _tmp;
     } else if ( _tmp.length > 2 ) {
       _tmp = _tmp.substring( _tmp.length - 2 );
     }
     _obj.y = _tmp;
   } else {
     _obj.y = _obj.Y;
   }

   var _check = [ 'd' , 'm' , 'H' , 'M' , 'S' ];
   for ( var i in _check ) {
     _tmp = _obj[ _check[ i ] ];
     _tmp = _tmp.toString( );
     if ( _tmp.length < 2 ) {
       _tmp = '0' + _tmp;
     }
     _obj[ _check[ i ] ] = _tmp;
   }

   return _obj;
 };

 var _dateTimeToDtObj = function ( dateTime , utc ) {
   var _obj, _month, _dow;
   if ( utc ) {
     _obj = {
       'H' : dateTime.getUTCHours( ) ,
       'M' : dateTime.getUTCMinutes( ) ,
       'S' : dateTime.getUTCSeconds( ) ,
       'd' : dateTime.getUTCDate( ) ,
       'Y' : dateTime.getUTCFullYear( )
     };
     _month = dateTime.getUTCMonth( );
     _dow = dateTime.getUTCDay( );
   } else {
     _obj = {
       'H' : dateTime.getHours( ) ,
       'M' : dateTime.getMinutes( ) ,
       'S' : dateTime.getSeconds( ) ,
       'd' : dateTime.getDate( ) ,
       'Y' : dateTime.getFullYear( )
     };
     _month = dateTime.getMonth( );
     _dow = dateTime.getDay( );
   }
   return _finaliseObj( _obj , _month , _dow );
 };

 var _objToDtObj = function ( obj ) {
   var _defs = {
     'H' : 0 ,
     'M' : 0 ,
     'S' : 0 ,
     'd' : 1 ,
     'Y' : 1 ,
     'm' : 1
   };
   var _dtObj = {};

   for ( var i in _defs ) {
     if ( typeof obj[ i ] != 'number' || obj[ i ] % 1 != 0 ) {
       _dtObj[ i ] = _defs[ i ];
     } else {
       _dtObj[ i ] = obj[ i ];
     }
   }

   _dtObj.m --;

   var _dow;
   if ( typeof obj.dow == 'number' && obj.dow % 1 == 0 ) {
     _dow = obj.dow;
   } else {
     _dow = 0;
   }

   return _finaliseObj( _dtObj , _dtObj.m , _dow );
 };

 $.strftime = function ( fmt , dateTime , utc ) {

   if ( fmt && typeof fmt == 'object' ) {
     dateTime = fmt.dateTime;
     utc = fmt.utc;
     fmt = fmt.format;
   }

   if ( !fmt || ( typeof fmt != 'string' ) ) {
     fmt = _useText.format;
   }

   var _dtObj;
   if ( dateTime && ( typeof dateTime == 'object' ) ) {
     if ( dateTime instanceof Date ) {
       _dtObj = _dateTimeToDtObj( dateTime , utc );
     } else {
       _dtObj = _objToDtObj( dateTime );
     }
   } else {
     _dtObj = _dateTimeToDtObj( new Date( ) , utc );
   }

   var _text = '' , _state = 0;
   for ( var i = 0 ; i < fmt.length ; i ++ ) {
     if ( _state == 0 ) {
       if ( fmt.charAt(i) == '%' ) {
         _state = 1;
       } else {
         _text += fmt.charAt( i );
       }
     } else {
       if ( typeof _dtObj[ fmt.charAt( i ) ] != 'undefined' ) {
         _text += _dtObj[ fmt.charAt( i ) ];
       } else {
         _text += '%';
         if ( fmt.charAt( i ) != '%' ) {
           _text += fmt.charAt( i );
         }
       }
       _state = 0;
     }
   }
   if ( _state == 1 ) {
     _text += '%';
   }

   return _text;
 };


 $.extend( $.strftime , {
   setText: function ( obj ) {
     if ( typeof obj != 'object' ) {
       throw new Error( '$.strftime.setText() : invalid parameter' );
     }

     var _count = 0;
     for ( var i in obj ) {
       if ( typeof _defaults[ i ] == 'undefined' ) {
         throw new Error( '$.strftime.setText() : invalid field "' + i + '"' );
       } else if ( i == 'format' && typeof obj[ i ] != 'string' ) {
         throw new Error( '$.strftime.setText() : invalid type for the "format" field' );
       } else if ( i != 'format' && ! ( obj[ i ] instanceof Array ) ) {
         throw new Error( '$.strftime.setText() : field "' + i + '" should be an array' );
       } else if ( obj[ i ].length != _defaults[ i ].length ) {
         throw new Error( '$.strftime.setText() : field "' + i + '" has incorrect length '
             + obj[ i ].length + ' (should be ' + _defaults[ i ].length + ')'
                );
       }
       _count ++;
     }
     if ( _count != 5 ) {
       throw new Error( '$.strftime.setText() : 5 fields expected, ' + _count + ' found' );
     }

     _useText = obj;
   },

   defaults: function ( ) {
     _useText = _defaults;
   }
 } );

 $.fn.strftime = function ( fmt , dateTime , utc ) {
   var _text = $.strftime( fmt , dateTime , utc );
   return this.each( function( ) {
     $(this).html( _text );
   });
 };

});

/*!
 * jQuery Konami code trigger v. 0.1
 *
 * Copyright (c) 2009 Joe Mastey
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Usage:
 *  // konami code unlocks the tetris
 *  $('#tetris').konami(function(){
 *     $(this).show();
 *  });
 *
 *
 *  // enable all weapons on 'idkfa'.
 *  // note that each weapon must be unlocked by its own code entry
 *  $('.weapon').konami(function(){
 *     $(this).addClass('enabled');
 *  }, {'code':[73, 68, 75, 70, 65]});
 *
 *
 *  // listens on any element that can trigger a keyup event.
 *  // unlocks all weapons at once
 *  $(document).konami(function(){
 *     $('.weapon').addClass('enabled');
 *  }, {'code':[73, 68, 75, 70, 65]});
 *
 *
 */
(function($){
    $.fn.konami             = function( fn, params ) {
        params              = $.extend( {}, $.fn.konami.params, params );
        this.each(function(){
            var tgt         = $(this);
            tgt.bind( 'konami', fn )
               .bind( 'keyup', function(event) { $.fn.konami.checkCode( event, params, tgt ); } );
        });
        return this;
    };

    $.fn.konami.params      = {
        'code'      : [38, 38, 40, 40, 37, 39, 37, 39, 66, 65],
        'step'      : 0
    };

    $.fn.konami.checkCode   = function( event, params, tgt ) {
        if(event.keyCode == params.code[params.step]) {
            params.step++;
        } else {
            params.step     = 0;
        }

        if(params.step == params.code.length) {
            tgt.trigger('konami');
            params.step     = 0;
        }
    };
})(jQuery);

/*
 * jQuery JSONP Core Plugin 1.1.0 (2009-10-06)
 *
 * http://code.google.com/p/jquery-jsonp/
 *
 * Copyright (c) 2009 Julian Aubourg
 *
 * This document is licensed as free software under the terms of the
 * MIT License: http://www.opensource.org/licenses/mit-license.php
 */
(function($){

	// ###################### UTILITIES ##
	// Test a value is neither undefined nor null
	var defined = function(v) {
		return v!==undefined && v!==null;
	},
	// Call if defined
	callIfDefined = function(method,object,parameters) {
		defined(method) && method.apply(object,parameters);
	},
	// Let the current thread running
	later = function(functor) {
		setTimeout(functor,0);
	},
	// String constants (for better minification)
	empty="",
	amp="&",
	qMark="?",
	success = "success",
	error = "error",

	// Head element (for faster use)
	head = $("head"),
	// Page cache
	pageCache = {},

	// ###################### DEFAULT OPTIONS ##
	xOptionsDefaults = {
		//beforeSend: undefined,
		//cache: false,
		callback: "C",
		//callbackParameter: undefined,
		//complete: undefined,
		//data: ""
		//dataFilter: undefined,
		//error: undefined,
		//pageCache: false,
		//success: undefined,
		//timeout: 0,
		url: location.href
	},

	// ###################### MAIN FUNCTION ##
	jsonp = function(xOptions) {

		// Build data with default
		xOptions = $.extend({},xOptionsDefaults,xOptions);

		// References to beforeSend (for better minification)
		var beforeSendCallback = xOptions.beforeSend,

		// Abort/done flag
		done = 0;

		// Put a temporary abort
		xOptions.abort = function() { done = 1; };

		// Call beforeSend if provided (early abort if false returned)
		if (defined(beforeSendCallback) && (beforeSendCallback(xOptions,xOptions)===false || done))
			return xOptions;

		// References to xOptions members (for better minification)
		var successCallback = xOptions.success,
		completeCallback = xOptions.complete,
		errorCallback = xOptions.error,
		dataFilter = xOptions.dataFilter,
		callbackParameter = xOptions.callbackParameter,
		successCallbackName = xOptions.callback,
		cacheFlag = xOptions.cache,
		pageCacheFlag = xOptions.pageCache,
		url = xOptions.url,
		data = xOptions.data,
		timeout = xOptions.timeout,

		// Misc variables
		splitUrl,splitData,i,j;

		// Control entries
		url = defined(url)?url:empty;
		data = defined(data)?((typeof data)=="string"?data:$.param(data)):empty;

		// Add callback parameter if provided as option
		defined(callbackParameter)
			&& (data += (data==empty?empty:amp)+escape(callbackParameter)+"=?");

		// Add anticache parameter if needed
		!cacheFlag && !pageCacheFlag
			&& (data += (data==empty?empty:amp)+"_"+(new Date()).getTime()+"=");

		// Search for ? in url
		splitUrl = url.split(qMark);
		// Also in parameters if provided
		// (and merge arrays)
		if (data!=empty) {
			splitData = data.split(qMark);
			j = splitUrl.length-1;
			j && (splitUrl[j] += amp + splitData.shift());
			splitUrl = splitUrl.concat(splitData);
		}
		// If more than 2 ? replace the last one by the callback
		i = splitUrl.length-2;
		i && (splitUrl[i] += successCallbackName + splitUrl.pop());

		// Build the final url
		var finalUrl = splitUrl.join(qMark),

		// Utility function
		notifySuccess = function(json) {
			// Apply the data filter if provided
			defined(dataFilter) && (json = dataFilter.apply(xOptions,[json]));
			// Call success then complete
			callIfDefined(successCallback,xOptions,[json,success]);
			callIfDefined(completeCallback,xOptions,[xOptions,success]);
		},
	    notifyError = function(type) {
			// Call error then complete
			callIfDefined(errorCallback,xOptions,[xOptions,type]);
			callIfDefined(completeCallback,xOptions,[xOptions,type]);
	    },

	    // Get from pageCache
	    pageCached = pageCache[finalUrl];

		// Check page cache
		if (pageCacheFlag && defined(pageCached)) {
			later(function() {
				// If an error was cached
				defined(pageCached.s)
				? notifySuccess(pageCached.s)
				: notifyError(error);
			});
			return xOptions;
		}


		// Create & write to the iframe (sends the request)
		// We let the hand to current code to avoid
		// pre-emptive callbacks

		// We also install the timeout here to avoid
		// timeout before the code has been dumped to the frame
		// (in case of insanely short timeout values)
		later(function() {

			// If it has been aborted, do nothing
			if (done) return;

			// Create an iframe & add it to the document
			var frame = $("<iframe />").appendTo(head),

			// Get the iframe's window and document objects
			tmp = frame[0],
			window = tmp.contentWindow || tmp.contentDocument,
			document = window.document,

			// Declaration of cleanup function
			cleanUp,

			// Declaration of timer for timeout (so we can clear it eventually)
			timeoutTimer,

			// Error function
			errorFunction = function (_,type) {
				// If pure error (not timeout), cache if needed
				pageCacheFlag && !defined(type) && (pageCache[finalUrl] = empty);
				// Cleanup
				cleanUp();
				// Call error then complete
				notifyError(defined(type)?type:error);
			},

			// Iframe variable cleaning function
			removeVariable = function(varName) {
				window[varName] = undefined;
				try { delete window[varName]; } catch(_) {}
			},

			// Error callback name
			errorCallbackName = successCallbackName=="E"?"X":"E";

			// Control if we actually retrieved the document
			if(!defined(document)) {
				document = window;
			    window = document.getParentNode();
			}

			// We have to open the document before
			// declaring variables in the iframe's window
			// Don't ask me why, I have no clue
			document.open();

			// Install callbacks
			window[successCallbackName] = function(json) {
				// Set as treated
				done = 1;
				// Pagecache is needed
				pageCacheFlag && (pageCache[finalUrl] = {s: json});
				// Give hand back to frame
				// To finish gracefully
				later(function(){
					// Cleanup
					cleanUp();
					// Call success then complete
					notifySuccess(json);
				});
			};

			window[errorCallbackName] = function(state) {
				// If not treated, mark
				// then give hand back to iframe
				// for it to finish gracefully
				(!state || state=="complete") && !done++ && later(errorFunction);
			};

			// Clean up function (declaration)
			xOptions.abort = cleanUp = function() {
				// Clear the timeout (is it exists)
				clearTimeout(timeoutTimer);
				// Open the iframes document & clean
				document.open();
				removeVariable(errorCallbackName);
				removeVariable(successCallbackName);
				document.write(empty);
				document.close();
				frame.remove();
			};

			// Write to the document
			document.write([
				'<html><head><script src="',
				finalUrl,'" onload="',
				errorCallbackName,'()" onreadystatechange="',
				errorCallbackName,'(this.readyState)"></script></head><body onload="',
				errorCallbackName,'()"></body></html>'
			].join(empty)
			);

			// Close (makes some browsers happier)
			document.close();

			// If a timeout is needed, install it
			timeout>0 && (timeoutTimer = setTimeout(function(){
					!done && errorFunction(empty,"timeout");
			},timeout));
		});

		return xOptions;
	};

	// ###################### SETUP FUNCTION ##
	jsonp.setup = function(xOptions) {
		$.extend(xOptionsDefaults,xOptions);
	};

	// ###################### INSTALL in jQuery ##
	$.jsonp = jsonp;

})(jQuery);

(function($) {
  $.extend({
    get: function( url, data, success, failure, type ) {
      // shift arguments if data argument was ommited
      if ( $.isFunction( data ) ) {
        type = failure;
        failure = success;
        success = data;
        data = null;
      }

      // shift arguments if success argument was ommited
      if (success && !$.isFunction(success)) {
        type = success;
        success = null;
        failure = null;
      }
      // shift arguments if failure argument was ommited
      else if (failure && !$.isFunction(failure)) {
        type = failure;
        failure = null;
      }

      if (type == "jsonp" || url.match(/=\?/)) {
        return $.jsonp({
          url: url,
          data: data,
          success: success,
          error: failure,
          dataType: "json",
          callback: "callback"
          //timeout: 5000
        });
      } else {
        return $.ajax({
          type: "GET",
          url: url,
          data: data,
          success: success,
          error: failure,
          dataType: type
        });
      }
    }
  });
  $.extend({
    /*getScript: function( url, success, failure ) {
      return $.get(url, null, success, failure, "script");
    },*/

    getJSON: function( url, data, success, failure ) {
      return $.get(url, data, success, failure || "json", "json");
    },

    post: function( url, data, success, failure, type ) {
      // shift arguments if data argument was ommited
      if ( $.isFunction( data ) ) {
        type = failure;
        failure = success;
        success = data;
        data = {};
      }

      // shift arguments if success argument was ommited
      if (success && !$.isFunction(success)) {
        type = success;
        success = null;
        failure = null;
      }
      // shift arguments if failure argument was ommited
      else if (failure && !$.isFunction(failure)) {
        type = failure;
        failure = null;
      }

      return $.ajax({
        type: "POST",
        url: url,
        data: data,
        success: success,
        error: failure,
        dataType: type
      });
    }
  });
})(jQuery);

/*!
 * jQuery blockUI plugin
 * Version 2.28 (02-DEC-2009)
 * @requires jQuery v1.2.3 or later
 *
 * Examples at: http://malsup.com/jquery/block/
 * Copyright (c) 2007-2008 M. Alsup
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * Thanks to Amir-Hossein Sobhi for some excellent contributions!
 */

;(function($) {

if (/1\.(0|1|2)\.(0|1|2)/.test($.fn.jquery) || /^1.1/.test($.fn.jquery)) {
	alert('blockUI requires jQuery v1.2.3 or later!  You are using v' + $.fn.jquery);
	return;
}

$.fn._fadeIn = $.fn.fadeIn;

// this bit is to ensure we don't call setExpression when we shouldn't (with extra muscle to handle
// retarded userAgent strings on Vista)
var mode = document.documentMode || 0;
var setExpr = $.browser.msie && (($.browser.version < 8 && !mode) || mode < 8);
var ie6 = $.browser.msie && /MSIE 6.0/.test(navigator.userAgent) && !mode;

// global $ methods for blocking/unblocking the entire page
$.blockUI   = function(opts) { install(window, opts); };
$.unblockUI = function(opts) { remove(window, opts); };

// convenience method for quick growl-like notifications  (http://www.google.com/search?q=growl)
$.growlUI = function(title, message, timeout, onClose) {
	var $m = $('<div class="growlUI"></div>');
	if (title) $m.append('<h1>'+title+'</h1>');
	if (message) $m.append('<h2>'+message+'</h2>');
	if (timeout == undefined) timeout = 3000;
	$.blockUI({
		message: $m, fadeIn: 700, fadeOut: 1000, centerY: false,
		timeout: timeout, showOverlay: false,
		onUnblock: onClose, 
		css: $.blockUI.defaults.growlCSS
	});
};

// plugin method for blocking element content
$.fn.block = function(opts) {
	return this.unblock({ fadeOut: 0 }).each(function() {
		if ($.css(this,'position') == 'static')
			this.style.position = 'relative';
		if ($.browser.msie)
			this.style.zoom = 1; // force 'hasLayout'
		install(this, opts);
	});
};

// plugin method for unblocking element content
$.fn.unblock = function(opts) {
	return this.each(function() {
		remove(this, opts);
	});
};

$.blockUI.version = 2.28; // 2nd generation blocking at no extra cost!

// override these in your code to change the default behavior and style
$.blockUI.defaults = {
	// message displayed when blocking (use null for no message)
	message:  '<h1>Please wait...</h1>',

	title: null,	  // title string; only used when theme == true
	draggable: true,  // only used when theme == true (requires jquery-ui.js to be loaded)
	
	theme: false, // set to true to use with jQuery UI themes
	
	// styles for the message when blocking; if you wish to disable
	// these and use an external stylesheet then do this in your code:
	// $.blockUI.defaults.css = {};
	css: {
		padding:	0,
		margin:		0,
		width:		'30%',
		top:		'40%',
		left:		'35%',
		textAlign:	'center',
		color:		'#000',
		border:		'3px solid #aaa',
		backgroundColor:'#fff',
		cursor:		'wait'
	},
	
	// minimal style set used when themes are used
	themedCSS: {
		width:	'30%',
		top:	'40%',
		left:	'35%'
	},

	// styles for the overlay
	overlayCSS:  {
		backgroundColor: '#000',
		opacity:	  	 0.6,
		cursor:		  	 'wait'
	},

	// styles applied when using $.growlUI
	growlCSS: {
		width:  	'350px',
		top:		'10px',
		left:   	'',
		right:  	'10px',
		border: 	'none',
		padding:	'5px',
		opacity:	0.6,
		cursor: 	'default',
		color:		'#fff',
		backgroundColor: '#000',
		'-webkit-border-radius': '10px',
		'-moz-border-radius':	 '10px'
	},
	
	// IE issues: 'about:blank' fails on HTTPS and javascript:false is s-l-o-w
	// (hat tip to Jorge H. N. de Vasconcelos)
	iframeSrc: /^https/i.test(window.location.href || '') ? 'javascript:false' : 'about:blank',

	// force usage of iframe in non-IE browsers (handy for blocking applets)
	forceIframe: false,

	// z-index for the blocking overlay
	baseZ: 1000,

	// set these to true to have the message automatically centered
	centerX: true, // <-- only effects element blocking (page block controlled via css above)
	centerY: true,

	// allow body element to be stetched in ie6; this makes blocking look better
	// on "short" pages.  disable if you wish to prevent changes to the body height
	allowBodyStretch: true,

	// enable if you want key and mouse events to be disabled for content that is blocked
	bindEvents: true,

	// be default blockUI will supress tab navigation from leaving blocking content
	// (if bindEvents is true)
	constrainTabKey: true,

	// fadeIn time in millis; set to 0 to disable fadeIn on block
	fadeIn:  200,

	// fadeOut time in millis; set to 0 to disable fadeOut on unblock
	fadeOut:  400,

	// time in millis to wait before auto-unblocking; set to 0 to disable auto-unblock
	timeout: 0,

	// disable if you don't want to show the overlay
	showOverlay: true,

	// if true, focus will be placed in the first available input field when
	// page blocking
	focusInput: true,

	// suppresses the use of overlay styles on FF/Linux (due to performance issues with opacity)
	applyPlatformOpacityRules: true,

	// callback method invoked when unblocking has completed; the callback is
	// passed the element that has been unblocked (which is the window object for page
	// blocks) and the options that were passed to the unblock call:
	//	 onUnblock(element, options)
	onUnblock: null,

	// don't ask; if you really must know: http://groups.google.com/group/jquery-en/browse_thread/thread/36640a8730503595/2f6a79a77a78e493#2f6a79a77a78e493
	quirksmodeOffsetHack: 4
};

// private data and functions follow...

var pageBlock = null;
var pageBlockEls = [];

function install(el, opts) {
	var full = (el == window);
	var msg = opts && opts.message !== undefined ? opts.message : undefined;
	opts = $.extend({}, $.blockUI.defaults, opts || {});
	opts.overlayCSS = $.extend({}, $.blockUI.defaults.overlayCSS, opts.overlayCSS || {});
	var css = $.extend({}, $.blockUI.defaults.css, opts.css || {});
	var themedCSS = $.extend({}, $.blockUI.defaults.themedCSS, opts.themedCSS || {});
	msg = msg === undefined ? opts.message : msg;

	// remove the current block (if there is one)
	if (full && pageBlock)
		remove(window, {fadeOut:0});

	// if an existing element is being used as the blocking content then we capture
	// its current place in the DOM (and current display style) so we can restore
	// it when we unblock
	if (msg && typeof msg != 'string' && (msg.parentNode || msg.jquery)) {
		var node = msg.jquery ? msg[0] : msg;
		var data = {};
		$(el).data('blockUI.history', data);
		data.el = node;
		data.parent = node.parentNode;
		data.display = node.style.display;
		data.position = node.style.position;
		if (data.parent)
			data.parent.removeChild(node);
	}

	var z = opts.baseZ;

	// blockUI uses 3 layers for blocking, for simplicity they are all used on every platform;
	// layer1 is the iframe layer which is used to supress bleed through of underlying content
	// layer2 is the overlay layer which has opacity and a wait cursor (by default)
	// layer3 is the message content that is displayed while blocking

	var lyr1 = ($.browser.msie || opts.forceIframe) 
		? $('<iframe class="blockUI" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;position:absolute;width:100%;height:100%;top:0;left:0" src="'+opts.iframeSrc+'"></iframe>')
		: $('<div class="blockUI" style="display:none"></div>');
	var lyr2 = $('<div class="blockUI blockOverlay" style="z-index:'+ (z++) +';display:none;border:none;margin:0;padding:0;width:100%;height:100%;top:0;left:0"></div>');
	
	var lyr3;
	if (opts.theme && full) {
		var s = '<div class="blockUI blockMsg blockPage ui-dialog ui-widget ui-corner-all" style="z-index:'+z+';display:none;position:fixed">' +
					'<div class="ui-widget-header ui-dialog-titlebar blockTitle">'+(opts.title || '&nbsp;')+'</div>' +
					'<div class="ui-widget-content ui-dialog-content"></div>' +
				'</div>';
		lyr3 = $(s);
	}
	else {
		lyr3 = full ? $('<div class="blockUI blockMsg blockPage" style="z-index:'+z+';display:none;position:fixed"></div>')
					: $('<div class="blockUI blockMsg blockElement" style="z-index:'+z+';display:none;position:absolute"></div>');
	}						   

	// if we have a message, style it
	if (msg) {
		if (opts.theme) {
			lyr3.css(themedCSS);
			lyr3.addClass('ui-widget-content');
		}
		else 
			lyr3.css(css);
	}

	// style the overlay
	if (!opts.applyPlatformOpacityRules || !($.browser.mozilla && /Linux/.test(navigator.platform)))
		lyr2.css(opts.overlayCSS);
	lyr2.css('position', full ? 'fixed' : 'absolute');

	// make iframe layer transparent in IE
	if ($.browser.msie || opts.forceIframe)
		lyr1.css('opacity',0.0);

	$([lyr1[0],lyr2[0],lyr3[0]]).appendTo(full ? 'body' : el);
	
	if (opts.theme && opts.draggable && $.fn.draggable) {
		lyr3.draggable({
			handle: '.ui-dialog-titlebar',
			cancel: 'li'
		});
	}

	// ie7 must use absolute positioning in quirks mode and to account for activex issues (when scrolling)
	var expr = setExpr && (!$.boxModel || $('object,embed', full ? null : el).length > 0);
	if (ie6 || expr) {
		// give body 100% height
		if (full && opts.allowBodyStretch && $.boxModel)
			$('html,body').css('height','100%');

		// fix ie6 issue when blocked element has a border width
		if ((ie6 || !$.boxModel) && !full) {
			var t = sz(el,'borderTopWidth'), l = sz(el,'borderLeftWidth');
			var fixT = t ? '(0 - '+t+')' : 0;
			var fixL = l ? '(0 - '+l+')' : 0;
		}

		// simulate fixed position
		$.each([lyr1,lyr2,lyr3], function(i,o) {
			var s = o[0].style;
			s.position = 'absolute';
			if (i < 2) {
				full ? s.setExpression('height','Math.max(document.body.scrollHeight, document.body.offsetHeight) - (jQuery.boxModel?0:'+opts.quirksmodeOffsetHack+') + "px"')
					 : s.setExpression('height','this.parentNode.offsetHeight + "px"');
				full ? s.setExpression('width','jQuery.boxModel && document.documentElement.clientWidth || document.body.clientWidth + "px"')
					 : s.setExpression('width','this.parentNode.offsetWidth + "px"');
				if (fixL) s.setExpression('left', fixL);
				if (fixT) s.setExpression('top', fixT);
			}
			else if (opts.centerY) {
				if (full) s.setExpression('top','(document.documentElement.clientHeight || document.body.clientHeight) / 2 - (this.offsetHeight / 2) + (blah = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + "px"');
				s.marginTop = 0;
			}
			else if (!opts.centerY && full) {
				var top = (opts.css && opts.css.top) ? parseInt(opts.css.top) : 0;
				var expression = '((document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop) + '+top+') + "px"';
				s.setExpression('top',expression);
			}
		});
	}

	// show the message
	if (msg) {
		if (opts.theme)
			lyr3.find('.ui-widget-content').append(msg);
		else
			lyr3.append(msg);
		if (msg.jquery || msg.nodeType)
			$(msg).show();
	}

	if (($.browser.msie || opts.forceIframe) && opts.showOverlay)
		lyr1.show(); // opacity is zero
	if (opts.fadeIn) {
		if (opts.showOverlay)
			lyr2._fadeIn(opts.fadeIn);
		if (msg)
			lyr3.fadeIn(opts.fadeIn);
	}
	else {
		if (opts.showOverlay)
			lyr2.show();
		if (msg)
			lyr3.show();
	}

	// bind key and mouse events
	bind(1, el, opts);

	if (full) {
		pageBlock = lyr3[0];
		pageBlockEls = $(':input:enabled:visible',pageBlock);
		if (opts.focusInput)
			setTimeout(focus, 20);
	}
	else
		center(lyr3[0], opts.centerX, opts.centerY);

	if (opts.timeout) {
		// auto-unblock
		var to = setTimeout(function() {
			full ? $.unblockUI(opts) : $(el).unblock(opts);
		}, opts.timeout);
		$(el).data('blockUI.timeout', to);
	}
};

// remove the block
function remove(el, opts) {
	var full = (el == window);
	var $el = $(el);
	var data = $el.data('blockUI.history');
	var to = $el.data('blockUI.timeout');
	if (to) {
		clearTimeout(to);
		$el.removeData('blockUI.timeout');
	}
	opts = $.extend({}, $.blockUI.defaults, opts || {});
	bind(0, el, opts); // unbind events
	
	var els;
	if (full) // crazy selector to handle odd field errors in ie6/7
		els = $('body').children().filter('.blockUI').add('body > .blockUI');
	else
		els = $('.blockUI', el);

	if (full)
		pageBlock = pageBlockEls = null;

	if (opts.fadeOut) {
		els.fadeOut(opts.fadeOut);
		setTimeout(function() { reset(els,data,opts,el); }, opts.fadeOut);
	}
	else
		reset(els, data, opts, el);
};

// move blocking element back into the DOM where it started
function reset(els,data,opts,el) {
	els.each(function(i,o) {
		// remove via DOM calls so we don't lose event handlers
		if (this.parentNode)
			this.parentNode.removeChild(this);
	});

	if (data && data.el) {
		data.el.style.display = data.display;
		data.el.style.position = data.position;
		if (data.parent)
			data.parent.appendChild(data.el);
		$(el).removeData('blockUI.history');
	}

	if (typeof opts.onUnblock == 'function')
		opts.onUnblock(el,opts);
};

// bind/unbind the handler
function bind(b, el, opts) {
	var full = el == window, $el = $(el);

	// don't bother unbinding if there is nothing to unbind
	if (!b && (full && !pageBlock || !full && !$el.data('blockUI.isBlocked')))
		return;
	if (!full)
		$el.data('blockUI.isBlocked', b);

	// don't bind events when overlay is not in use or if bindEvents is false
	if (!opts.bindEvents || (b && !opts.showOverlay)) 
		return;

	// bind anchors and inputs for mouse and key events
	var events = 'mousedown mouseup keydown keypress';
	b ? $(document).bind(events, opts, handler) : $(document).unbind(events, handler);

// former impl...
//	   var $e = $('a,:input');
//	   b ? $e.bind(events, opts, handler) : $e.unbind(events, handler);
};

// event handler to suppress keyboard/mouse events when blocking
function handler(e) {
	// allow tab navigation (conditionally)
	if (e.keyCode && e.keyCode == 9) {
		if (pageBlock && e.data.constrainTabKey) {
			var els = pageBlockEls;
			var fwd = !e.shiftKey && e.target == els[els.length-1];
			var back = e.shiftKey && e.target == els[0];
			if (fwd || back) {
				setTimeout(function(){focus(back)},10);
				return false;
			}
		}
	}
	// allow events within the message content
	if ($(e.target).parents('div.blockMsg').length > 0)
		return true;

	// allow events for content that is not being blocked
	return $(e.target).parents().children().filter('div.blockUI').length == 0;
};

function focus(back) {
	if (!pageBlockEls)
		return;
	var e = pageBlockEls[back===true ? pageBlockEls.length-1 : 0];
	if (e)
		e.focus();
};

function center(el, x, y) {
	var p = el.parentNode, s = el.style;
	var l = ((p.offsetWidth - el.offsetWidth)/2) - sz(p,'borderLeftWidth');
	var t = ((p.offsetHeight - el.offsetHeight)/2) - sz(p,'borderTopWidth');
	if (x) s.left = l > 0 ? (l+'px') : '0';
	if (y) s.top  = t > 0 ? (t+'px') : '0';
};

function sz(el, p) {
	return parseInt($.css(el,p))||0;
};

})(jQuery);
