/*
 * jqModal - Minimalist Modaling with jQuery
 *   (http://dev.iceburg.net/jquery/jqModal/)
 *
 * Copyright (c) 2007,2008 Brice Burgess <bhb@iceburg.net>
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * $Version: 07/06/2008 +r13
 */
(function($) {
$.fn.jqm=function(o){
var p={
overlay: 50,
overlayClass: 'jqmOverlay',
closeClass: 'jqmClose',
trigger: '.jqModal',
ajax: F,
ajaxText: '',
target: F,
modal: F,
toTop: F,
onShow: F,
onHide: F,
onLoad: F
};
return this.each(function(){if(this._jqm)return H[this._jqm].c=$.extend({},H[this._jqm].c,o);s++;this._jqm=s;
H[s]={c:$.extend(p,$.jqm.params,o),a:F,w:$(this).addClass('jqmID'+s),s:s};
if(p.trigger)$(this).jqmAddTrigger(p.trigger);
});};

$.fn.jqmAddClose=function(e){return hs(this,e,'jqmHide');};
$.fn.jqmAddTrigger=function(e){return hs(this,e,'jqmShow');};
$.fn.jqmShow=function(t){return this.each(function(){$.jqm.open(this._jqm,t);});};
$.fn.jqmHide=function(t){return this.each(function(){$.jqm.close(this._jqm,t)});};

$.jqm = {
hash:{},
open:function(s,t){var h=H[s],c=h.c,cc='.'+c.closeClass,z=(parseInt(h.w.css('z-index'))),z=(z>0)?z:3000,o=$('<div></div>').css({height:'100%',width:'100%',position:'fixed',left:0,top:0,'z-index':z-1,opacity:c.overlay/100});if(h.a)return F;h.t=t;h.a=true;h.w.css('z-index',z);
 if(c.modal) {if(!A[0])L('bind');A.push(s);}
 else if(c.overlay > 0)h.w.jqmAddClose(o);
 else o=F;

 h.o=(o)?o.addClass(c.overlayClass).prependTo('body'):F;
 if(ie6){$('html,body').css({height:'100%',width:'100%'});if(o){o=o.css({position:'absolute'})[0];for(var y in {Top:1,Left:1})o.style.setExpression(y.toLowerCase(),"(_=(document.documentElement.scroll"+y+" || document.body.scroll"+y+"))+'px'");}}

 if(c.ajax) {var r=c.target||h.w,u=c.ajax,r=(typeof r == 'string')?$(r,h.w):$(r),u=(u.substr(0,1) == '@')?$(t).attr(u.substring(1)):u;
  r.html(c.ajaxText).load(u,function(){if(c.onLoad)c.onLoad.call(this,h);if(cc)h.w.jqmAddClose($(cc,h.w));e(h);});}
 else if(cc)h.w.jqmAddClose($(cc,h.w));

 if(c.toTop&&h.o)h.w.before('<span id="jqmP'+h.w[0]._jqm+'"></span>').insertAfter(h.o);
 (c.onShow)?c.onShow(h):h.w.show();e(h);return F;
},
close:function(s){var h=H[s];if(!h.a)return F;h.a=F;
 if(A[0]){A.pop();if(!A[0])L('unbind');}
 if(h.c.toTop&&h.o)$('#jqmP'+h.w[0]._jqm).after(h.w).remove();
 if(h.c.onHide)h.c.onHide(h);else{h.w.hide();if(h.o)h.o.remove();} return F;
},
params:{}};
var s=0,H=$.jqm.hash,A=[],ie6=$.browser.msie&&($.browser.version == "6.0"),F=false,
i=$('<iframe src="javascript:false;document.write(\'\');" class="jqm"></iframe>').css({opacity:0}),
e=function(h){if(ie6)if(h.o)h.o.html('<p style="width:100%;height:100%"/>').prepend(i);else if(!$('iframe.jqm',h.w)[0])h.w.prepend(i); f(h);},
f=function(h){try{$(':input:visible',h.w)[0].focus();}catch(_){}},
L=function(t){$()[t]("keypress",m)[t]("keydown",m)[t]("mousedown",m);},
m=function(e){var h=H[A[A.length-1]],r=(!$(e.target).parents('.jqmID'+h.s)[0]);if(r)f(h);return !r;},
hs=function(w,t,c){return w.each(function(){var s=this._jqm;$(t).each(function() {
 if(!this[c]){this[c]=[];$(this).click(function(){for(var i in {jqmShow:1,jqmHide:1})for(var s in this[i])if(H[this[i][s]])H[this[i][s]].w[i](this);return F;});}this[c].push(s);});});};
})(jQuery);
/* Copyright (c) 2006 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: 2007-06-20 03:23:36 +0200 (Mi, 20 Jun 2007) $
 * $Rev: 2110 $
 *
 * Version 2.1
 */

(function($){

/**
 * The bgiframe is chainable and applies the iframe hack to get 
 * around zIndex issues in IE6. It will only apply itself in IE 
 * and adds a class to the iframe called 'bgiframe'. The iframe
 * is appeneded as the first child of the matched element(s) 
 * with a tabIndex and zIndex of -1.
 * 
 * By default the plugin will take borders, sized with pixel units,
 * into account. If a different unit is used for the border's width,
 * then you will need to use the top and left settings as explained below.
 *
 * NOTICE: This plugin has been reported to cause perfromance problems
 * when used on elements that change properties (like width, height and
 * opacity) a lot in IE6. Most of these problems have been caused by 
 * the expressions used to calculate the elements width, height and 
 * borders. Some have reported it is due to the opacity filter. All 
 * these settings can be changed if needed as explained below.
 *
 * @example $('div').bgiframe();
 * @before <div><p>Paragraph</p></div>
 * @result <div><iframe class="bgiframe".../><p>Paragraph</p></div>
 *
 * @param Map settings Optional settings to configure the iframe.
 * @option String|Number top The iframe must be offset to the top
 * 		by the width of the top border. This should be a negative 
 *      number representing the border-top-width. If a number is 
 * 		is used here, pixels will be assumed. Otherwise, be sure
 *		to specify a unit. An expression could also be used. 
 * 		By default the value is "auto" which will use an expression 
 * 		to get the border-top-width if it is in pixels.
 * @option String|Number left The iframe must be offset to the left
 * 		by the width of the left border. This should be a negative 
 *      number representing the border-left-width. If a number is 
 * 		is used here, pixels will be assumed. Otherwise, be sure
 *		to specify a unit. An expression could also be used. 
 * 		By default the value is "auto" which will use an expression 
 * 		to get the border-left-width if it is in pixels.
 * @option String|Number width This is the width of the iframe. If
 *		a number is used here, pixels will be assume. Otherwise, be sure
 * 		to specify a unit. An experssion could also be used.
 *		By default the value is "auto" which will use an experssion
 * 		to get the offsetWidth.
 * @option String|Number height This is the height of the iframe. If
 *		a number is used here, pixels will be assume. Otherwise, be sure
 * 		to specify a unit. An experssion could also be used.
 *		By default the value is "auto" which will use an experssion
 * 		to get the offsetHeight.
 * @option Boolean opacity This is a boolean representing whether or not
 * 		to use opacity. If set to true, the opacity of 0 is applied. If
 *		set to false, the opacity filter is not applied. Default: true.
 * @option String src This setting is provided so that one could change 
 *		the src of the iframe to whatever they need.
 *		Default: "javascript:false;"
 *
 * @name bgiframe
 * @type jQuery
 * @cat Plugins/bgiframe
 * @author Brandon Aaron (brandon.aaron@gmail.com || http://brandonaaron.net)
 */
$.fn.bgIframe = $.fn.bgiframe = function(s) {
	// This is only for IE6
	if ( $.browser.msie && parseInt($.browser.version) <= 6 ) {
		s = $.extend({
			top     : 'auto', // auto == .currentStyle.borderTopWidth
			left    : 'auto', // auto == .currentStyle.borderLeftWidth
			width   : 'auto', // auto == offsetWidth
			height  : 'auto', // auto == offsetHeight
			opacity : true,
			src     : 'javascript:false;'
		}, s || {});
		var prop = function(n){return n&&n.constructor==Number?n+'px':n;},
		    html = '<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+
		               'style="display:block;position:absolute;z-index:-1;'+
			               (s.opacity !== false?'filter:Alpha(Opacity=\'0\');':'')+
					       'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+
					       'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+
					       'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+
					       'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+
					'"/>';
		return this.each(function() {
			if ( $('> iframe.bgiframe', this).length == 0 )
				this.insertBefore( document.createElement(html), this.firstChild );
		});
	}
	return this;
};

// Add browser.version if it doesn't exist
if (!$.browser.version)
	$.browser.version = navigator.userAgent.toLowerCase().match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)[1];

})(jQuery);
/*
 * @name BeautyTips
 * @desc a tooltips/baloon-help plugin for jQuery
 *
 * @author Jeff Robbins - Lullabot - http://www.lullabot.com
 * @version 0.9.1  (2/15/2009)
 *  
 * @type jQuery
 * @cat Plugins/bt
 * @requires jQuery v1.2+ (not tested on versions prior to 1.2.6)
 *
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 *
 * Encourage development. If you use BeautyTips for anything cool 
 * or on a site that people have heard of, please drop me a note.
 * - jeff ^at lullabot > com
 *
 * No guarantees, warranties, or promises of any kind
 *
 */

/**
 * @credit Inspired by Karl Swedberg's ClueTip
 *    (http://plugins.learningjquery.com/cluetip/), which in turn was inspired
 *    by Cody Lindley's jTip (http://www.codylindley.com)
 *
 * @fileoverview
 * Beauty Tips is a jQuery tooltips plugin which uses the canvas drawing element
 * in the HTML5 spec in order to dynamically draw tooltip "talk bubbles" around
 * the descriptive help text associated with an item. This is in many ways
 * similar to Google Maps which both provides similar talk-bubbles and uses the
 * canvas element to draw them.
 *
 * The canvas element is supported in modern versions of FireFox, Safari, and
 * Opera. However, Internet Explorer needs a separate library called ExplorerCanvas
 * included on the page in order to support canvas drawing functions. ExplorerCanvas
 * was created by Google for use with their web apps and you can find it here:
 * http://excanvas.sourceforge.net/
 *
 * Beauty Tips was written to be simple to use and pretty. All of its options
 * are documented at the bottom of this file and defaults can be overwritten
 * globally for the entire page, or individually on each call.
 *
 * By default each tooltip will be positioned on the side of the target element
 * which has the most free space. This is affected by the scroll position and
 * size of the current window, so each Beauty Tip is redrawn each time it is
 * displayed. It may appear above an element at the bottom of the page, but when
 * the page is scrolled down (and the element is at the top of the page) it will
 * then appear below it. Additionally, positions can be forced or a preferred
 * order can be defined. See examples below.
 *
 * To fix z-index problems in IE6, include the bgiframe plugin on your page
 * http://plugins.jquery.com/project/bgiframe - BeautyTips will automatically
 * recognize it and use it.
 *
 * BeautyTips also works with the hoverIntent plugin
 * http://cherne.net/brian/resources/jquery.hoverIntent.html
 * see hoverIntent example below for usage
 *
 * Usage
 * The function can be called in a number of ways.
 * $(selector).bt();
 * $(selector).bt('Content text');
 * $(selector).bt('Content text', {option1: value, option2: value});
 * $(selector).bt({option1: value, option2: value});
 *
 * For more/better documentation and lots of examples, visit the demo page included with the distribution
 *
 */
jQuery.fn.bt = function(content, options) {

  if (typeof content != 'string') {
    var contentSelect = true;
    options = content;
    content = false;
  }
  else {
    var contentSelect = false;
  }
  
  // if hoverIntent is installed, use that as default instead of hover
  if (jQuery.fn.hoverIntent && jQuery.bt.defaults.trigger == 'hover') {
    jQuery.bt.defaults.trigger = 'hoverIntent';
  }

  return this.each(function(index) {

    var opts = jQuery.extend(false, jQuery.bt.defaults, options);

    // clean up the options
    opts.spikeLength = numb(opts.spikeLength);
    opts.spikeGirth = numb(opts.spikeGirth);
    opts.overlap = numb(opts.overlap);
    
    var ajaxTimeout = false;
    
    /**
     * This is sort of the "starting spot" for the this.each()
     * These are sort of the init functions to handle the call
     */

    if (opts.killTitle) {
      $(this).find('[title]').andSelf().each(function() {
        if (!$(this).attr('bt-xTitle')) {
          $(this).attr('bt-xTitle', $(this).attr('title')).attr('title', '');
        }
      });
    }    
    
    if (typeof opts.trigger == 'string') {
      opts.trigger = [opts.trigger];
    }
    if (opts.trigger[0] == 'hoverIntent') {
      var hoverOpts = $.extend(opts.hoverIntentOpts, {
        over: function() {
          this.btOn();
        },
        out: function() {
          this.btOff();
        }});
      $(this).hoverIntent(hoverOpts);
    
    }
    else if (opts.trigger[0] == 'hover') {
      $(this).hover(
        function() {
          this.btOn();
        },
        function() {
          this.btOff();
        }
      );
    }
    else if (opts.trigger[0] == 'now') {
      // toggle the on/off right now
      // note that 'none' gives more control (see below)
      if ($(this).hasClass('bt-active')) {
        this.btOff();
      }
      else {
        this.btOn();
      }
    }
    else if (opts.trigger[0] == 'none') {
      // initialize the tip with no event trigger
      // use javascript to turn on/off tip as follows:
      // $('#selector').btOn();
      // $('#selector').btOff();
    }
    else if (opts.trigger.length > 1 && opts.trigger[0] != opts.trigger[1]) {
      $(this)
        .bind(opts.trigger[0], function() {
          this.btOn();
        })
        .bind(opts.trigger[1], function() {
          this.btOff();
        });
    }
    else {
      // toggle using the same event
      $(this).bind(opts.trigger[0], function() {
        if ($(this).hasClass('bt-active')) {
          this.btOff();
        }
        else {
          this.btOn();
        }
      });
    }
    
    
    /**
     *  The BIG TURN ON
     *  Any element that has been initiated
     */
    this.btOn = function () {
      if (typeof $(this).data('bt-box') == 'object') {
        // if there's already a popup, remove it before creating a new one.
        this.btOff();
      }

      // trigger preShow function
      opts.preShow.apply(this);
      
      // turn off other tips
      $(jQuery.bt.vars.closeWhenOpenStack).btOff();
      
      // add the class to the target element (for hilighting, for example)
      // bt-active is always applied to all, but activeClass can apply another
      $(this).addClass('bt-active ' + opts.activeClass);

      if (contentSelect && opts.ajaxPath == null) {
        // bizarre, I know
        if (opts.killTitle) {
          // if we've killed the title attribute, it's been stored in 'bt-xTitle' so get it..
          $(this).attr('title', $(this).attr('bt-xTitle'));
        }
        // then evaluate the selector... title is now in place
        content = eval(opts.contentSelector);
        if (opts.killTitle) {
          // now remove the title again, so we don't get double tips
          $(this).attr('title', '');
        }
      }
      
      // ----------------------------------------------
      // All the Ajax(ish) stuff is in this next bit...
      // ----------------------------------------------
      if (opts.ajaxPath != null && content == false) {
        if (typeof opts.ajaxPath == 'object') {
          var url = eval(opts.ajaxPath[0]);
          url += opts.ajaxPath[1] ? ' ' + opts.ajaxPath[1] : '';
        }
        else {
          var url = opts.ajaxPath;
        }
        var off = url.indexOf(" ");
    		if ( off >= 0 ) {
    			var selector = url.slice(off, url.length);
    			url = url.slice(0, off);
    		}
      
        // load any data cached for the given ajax path
        var cacheData = opts.ajaxCache ? $(document.body).data('btCache-' + url.replace(/\./g, '')) : null;
        if (typeof cacheData == 'string') {
          content = selector ? jQuery("<div/>").append(cacheData.replace(/<script(.|\s)*?\/script>/g, "")).find(selector) : cacheData;
        }
        else {
          var target = this;
                    
          // set up the options
          var ajaxOpts = jQuery.extend(false,
          {
            type: opts.ajaxType,
            data: opts.ajaxData,
            cache: opts.ajaxCache,
            url: url,
            complete: function(XMLHttpRequest, textStatus) {
              if (textStatus == 'success' || textStatus == 'notmodified') {
                if (opts.ajaxCache) {
                  $(document.body).data('btCache-' + url.replace(/\./g, ''), XMLHttpRequest.responseText);
                }
                ajaxTimeout = false;
                content = selector ?
      						// Create a dummy div to hold the results
      						jQuery("<div/>")
      							// inject the contents of the document in, removing the scripts
      							// to avoid any 'Permission Denied' errors in IE
      							.append(XMLHttpRequest.responseText.replace(/<script(.|\s)*?\/script>/g, ""))
      
      							// Locate the specified elements
      							.find(selector) :
      
      						// If not, just inject the full result
      						XMLHttpRequest.responseText;
      				   
              }
              else {
                if (textStatus == 'timeout') {
                  // if there was a timeout, we don't cache the result
                  ajaxTimeout = true;
                }
                content = opts.ajaxError.replace(/%error/g, XMLHttpRequest.statusText);
              }
              // if the user rolls out of the target element before the ajax request comes back, don't show it
              if ($(target).hasClass('bt-active')) {
                target.btOn();
              }
            }
          }, opts.ajaxData);
          // do the ajax request
          $.ajax(ajaxOpts);
          // load the throbber while the magic happens
          content = opts.ajaxLoading;
        }
      }
      // </ ajax stuff >
      

      // now we start actually figuring out where to place the tip
      
      var offsetParent = $(this).offsetParent();
      var pos = $(this).btPosition();
      // top, left, width, and height values of the target element
      var top = numb(pos.top) + numb($(this).css('margin-top')); // IE can return 'auto' for margins
      var left = numb(pos.left) + numb($(this).css('margin-left'));
      var width = $(this).outerWidth();
      var height = $(this).outerHeight();
      
      if (typeof content == 'object') {
        // if content is a DOM object (as opposed to text)
        // use a clone, rather than removing the original element
        // and ensure that it's visible
        content = $(content).clone(true).show();
        
      }
      
      // create the tip content div, populate it, and style it
      var $text = $('<div class="bt-content"></div>').append(content).css({padding: opts.padding, position: 'absolute', width: opts.width, zIndex: opts.textzIndex}).css(opts.cssStyles);
      // create the wrapping box which contains text and canvas
      // put the content in it, style it, and append it to the same offset parent as the target
      var $box = $('<div class="bt-wrapper"></div>').append($text).addClass(opts.cssClass).css({position: 'absolute', width: opts.width, zIndex: opts.wrapperzIndex}).appendTo(offsetParent);
      
      // use bgiframe to get around z-index problems in IE6
      // http://plugins.jquery.com/project/bgiframe
      if ($.fn.bgiframe) {
        $text.bgiframe();
        $box.bgiframe();  
      }

      $(this).data('bt-box', $box);

      // see if the text box will fit in the various positions
      var scrollTop = numb($(document).scrollTop());
      var scrollLeft = numb($(document).scrollLeft());
      var docWidth = numb($(window).width());
      var docHeight = numb($(window).height());
      var winRight = scrollLeft + docWidth;
      var winBottom = scrollTop + docHeight;
      var space = new Object();
      space.top = $(this).offset().top - scrollTop;
      space.bottom = docHeight - (($(this).offset().top + height) - scrollTop);
      space.left = $(this).offset().left - scrollLeft;
      space.right = docWidth - (($(this).offset().left + width) - scrollLeft);
      var textOutHeight = numb($text.outerHeight());
      var textOutWidth = numb($text.outerWidth());
      if (opts.positions.constructor == String) {
        opts.positions = opts.positions.replace(/ /, '').split(',');
      }
      if (opts.positions[0] == 'most') {
        // figure out which is the largest
        var position = 'top'; // prime the pump
        for (var pig in space) { // pigs in space!
          position = space[pig] > space[position] ? pig : position;
        }
      }
      else {
        for (var x in opts.positions) {
          var position = opts.positions[x];
          if ((position == 'left' || position == 'right') && space[position] > textOutWidth + opts.spikeLength) {
            break;
          }
          else if ((position == 'top' || position == 'bottom') && space[position] > textOutHeight + opts.spikeLength) {
            break;
          }
        }
      }

      // horizontal (left) offset for the box
      var horiz = left + ((width - textOutWidth) * .5);
      // vertical (top) offset for the box
      var vert = top + ((height - textOutHeight) * .5);
      var animDist = opts.animate ? numb(opts.distance) : 0;
      var points = new Array();
      var textTop, textLeft, textRight, textBottom, textTopSpace, textBottomSpace, textLeftSpace, textRightSpace, crossPoint, textCenter, spikePoint;

      // Yes, yes, this next bit really could use to be condensed
      // each switch case is basically doing the same thing in slightly different ways
      switch(position) {
        case 'top':
          // spike on bottom
          $text.css('margin-bottom', opts.spikeLength + 'px');
          $box.css({top: (top - $text.outerHeight(true) - animDist) + opts.overlap, left: horiz});
          // move text left/right if extends out of window
          textRightSpace = (winRight - opts.windowMargin) - ($text.offset().left + $text.outerWidth(true));
          var xShift = 0;
          if (textRightSpace < 0) {
            // shift it left
            $box.css('left', (numb($box.css('left')) + textRightSpace) + 'px');
            xShift -= textRightSpace;
          }
          // we test left space second to ensure that left of box is visible
          textLeftSpace = ($text.offset().left + numb($text.css('margin-left'))) - (scrollLeft + opts.windowMargin);
          if (textLeftSpace < 0) {
            // shift it right
            $box.css('left', (numb($box.css('left')) - textLeftSpace) + 'px');
            xShift += textLeftSpace;
          }
          textTop = $text.btPosition().top + numb($text.css('margin-top'));
          textLeft = $text.btPosition().left + numb($text.css('margin-left'));
          textRight = textLeft + $text.outerWidth();
          textBottom = textTop + $text.outerHeight();
          textCenter = {x: textLeft + ($text.outerWidth()*opts.centerPointX), y: textTop + ($text.outerHeight()*opts.centerPointY)};
          // points[points.length] = {x: x, y: y};
          points[points.length] = spikePoint = {y: textBottom + opts.spikeLength, x: ((textRight-textLeft) * .5) + xShift, type: 'spike'};
          crossPoint = findIntersectX(spikePoint.x, spikePoint.y, textCenter.x, textCenter.y, textBottom);
          // make sure that the crossPoint is not outside of text box boundaries
          crossPoint.x = crossPoint.x < textLeft + opts.spikeGirth/2 + opts.cornerRadius ? textLeft + opts.spikeGirth/2 + opts.cornerRadius : crossPoint.x;
          crossPoint.x =  crossPoint.x > (textRight - opts.spikeGirth/2) - opts.cornerRadius ? (textRight - opts.spikeGirth/2) - opts.CornerRadius : crossPoint.x;
          points[points.length] = {x: crossPoint.x - (opts.spikeGirth/2), y: textBottom, type: 'join'};
          points[points.length] = {x: textLeft, y: textBottom, type: 'corner'};  // left bottom corner
          points[points.length] = {x: textLeft, y: textTop, type: 'corner'};     // left top corner
          points[points.length] = {x: textRight, y: textTop, type: 'corner'};    // right top corner
          points[points.length] = {x: textRight, y: textBottom, type: 'corner'}; // right bottom corner
          points[points.length] = {x: crossPoint.x + (opts.spikeGirth/2), y: textBottom, type: 'join'};
          points[points.length] = spikePoint;
          break;
        case 'left':
          // spike on right
          $text.css('margin-right', opts.spikeLength + 'px');
          $box.css({top: vert + 'px', left: ((left - $text.outerWidth(true) - animDist) + opts.overlap) + 'px'});
          // move text up/down if extends out of window
          textBottomSpace = (winBottom - opts.windowMargin) - ($text.offset().top + $text.outerHeight(true));
          var yShift = 0;
          if (textBottomSpace < 0) {
            // shift it up
            $box.css('top', (numb($box.css('top')) + textBottomSpace) + 'px');
            yShift -= textBottomSpace;
          }
          // we ensure top space second to ensure that top of box is visible
          textTopSpace = ($text.offset().top + numb($text.css('margin-top'))) - (scrollTop + opts.windowMargin);
          if (textTopSpace < 0) {
            // shift it down
            $box.css('top', (numb($box.css('top')) - textTopSpace) + 'px');
            yShift += textTopSpace;
          }
          textTop = $text.btPosition().top + numb($text.css('margin-top'));
          textLeft = $text.btPosition().left + numb($text.css('margin-left'));
          textRight = textLeft + $text.outerWidth();
          textBottom = textTop + $text.outerHeight();
          textCenter = {x: textLeft + ($text.outerWidth()*opts.centerPointX), y: textTop + ($text.outerHeight()*opts.centerPointY)};
          points[points.length] = spikePoint = {x: textRight + opts.spikeLength, y: ((textBottom-textTop) * .5) + yShift, type: 'spike'};
          crossPoint = findIntersectY(spikePoint.x, spikePoint.y, textCenter.x, textCenter.y, textRight);
          // make sure that the crossPoint is not outside of text box boundaries
          crossPoint.y = crossPoint.y < textTop + opts.spikeGirth/2 + opts.cornerRadius ? textTop + opts.spikeGirth/2 + opts.cornerRadius : crossPoint.y;
          crossPoint.y =  crossPoint.y > (textBottom - opts.spikeGirth/2) - opts.cornerRadius ? (textBottom - opts.spikeGirth/2) - opts.cornerRadius : crossPoint.y;
          points[points.length] = {x: textRight, y: crossPoint.y + opts.spikeGirth/2, type: 'join'};
          points[points.length] = {x: textRight, y: textBottom, type: 'corner'}; // right bottom corner
          points[points.length] = {x: textLeft, y: textBottom, type: 'corner'};  // left bottom corner
          points[points.length] = {x: textLeft, y: textTop, type: 'corner'};     // left top corner
          points[points.length] = {x: textRight, y: textTop, type: 'corner'};    // right top corner
          points[points.length] = {x: textRight, y: crossPoint.y - opts.spikeGirth/2, type: 'join'};
          points[points.length] = spikePoint;
          break;
        case 'bottom':
          // spike on top
          $text.css('margin-top', opts.spikeLength + 'px');
          $box.css({top: (top + height + animDist) - opts.overlap, left: horiz});
          // move text up/down if extends out of window
          textRightSpace = (winRight - opts.windowMargin) - ($text.offset().left + $text.outerWidth(true));
          var xShift = 0;
          if (textRightSpace < 0) {
            // shift it left
            $box.css('left', (numb($box.css('left')) + textRightSpace) + 'px');
            xShift -= textRightSpace;
          }
          // we ensure left space second to ensure that left of box is visible
          textLeftSpace = ($text.offset().left + numb($text.css('margin-left')))  - (scrollLeft + opts.windowMargin);
          if (textLeftSpace < 0) {
            // shift it right
            $box.css('left', (numb($box.css('left')) - textLeftSpace) + 'px');
            xShift += textLeftSpace;
          }
          textTop = $text.btPosition().top + numb($text.css('margin-top'));
          textLeft = $text.btPosition().left + numb($text.css('margin-left'));
          textRight = textLeft + $text.outerWidth();
          textBottom = textTop + $text.outerHeight();
          textCenter = {x: textLeft + ($text.outerWidth()*opts.centerPointX), y: textTop + ($text.outerHeight()*opts.centerPointY)};
          points[points.length] = spikePoint = {x: ((textRight-textLeft) * .5) + xShift, y: 0, type: 'spike'};
          crossPoint = findIntersectX(spikePoint.x, spikePoint.y, textCenter.x, textCenter.y, textTop);
          // make sure that the crossPoint is not outside of text box boundaries
          crossPoint.x = crossPoint.x < textLeft + opts.spikeGirth/2 + opts.cornerRadius ? textLeft + opts.spikeGirth/2 + opts.cornerRadius : crossPoint.x;
          crossPoint.x =  crossPoint.x > (textRight - opts.spikeGirth/2) - opts.cornerRadius ? (textRight - opts.spikeGirth/2) - opts.cornerRadius : crossPoint.x;
          points[points.length] = {x: crossPoint.x + opts.spikeGirth/2, y: textTop, type: 'join'};
          points[points.length] = {x: textRight, y: textTop, type: 'corner'};    // right top corner
          points[points.length] = {x: textRight, y: textBottom, type: 'corner'}; // right bottom corner
          points[points.length] = {x: textLeft, y: textBottom, type: 'corner'};  // left bottom corner
          points[points.length] = {x: textLeft, y: textTop, type: 'corner'};     // left top corner
          points[points.length] = {x: crossPoint.x - (opts.spikeGirth/2), y: textTop, type: 'join'};
          points[points.length] = spikePoint;
          break;
        case 'right':
          // spike on left
          $text.css('margin-left', (opts.spikeLength + 'px'));
          $box.css({top: vert + 'px', left: ((left + width + animDist) - opts.overlap) + 'px'});
          // move text up/down if extends out of window
          textBottomSpace = (winBottom - opts.windowMargin) - ($text.offset().top + $text.outerHeight(true));
          var yShift = 0;
          if (textBottomSpace < 0) {
            // shift it up
            $box.css('top', (numb($box.css('top')) + textBottomSpace) + 'px');
            yShift -= textBottomSpace;
          }
          // we ensure top space second to ensure that top of box is visible
          textTopSpace = ($text.offset().top + numb($text.css('margin-top'))) - (scrollTop + opts.windowMargin);
          if (textTopSpace < 0) {
            // shift it down
            $box.css('top', (numb($box.css('top')) - textTopSpace) + 'px');
            yShift += textTopSpace;
          }
          textTop = $text.btPosition().top + numb($text.css('margin-top'));
          textLeft = $text.btPosition().left + numb($text.css('margin-left'));
          textRight = textLeft + $text.outerWidth();
          textBottom = textTop + $text.outerHeight();
          textCenter = {x: textLeft + ($text.outerWidth()*opts.centerPointX), y: textTop + ($text.outerHeight()*opts.centerPointY)};
          points[points.length] = spikePoint = {x: 0, y: ((textBottom-textTop) * .5) + yShift, type: 'spike'};
          crossPoint = findIntersectY(spikePoint.x, spikePoint.y, textCenter.x, textCenter.y, textLeft);
          // make sure that the crossPoint is not outside of text box boundaries
          crossPoint.y = crossPoint.y < textTop + opts.spikeGirth/2 + opts.cornerRadius ? textTop + opts.spikeGirth/2 + opts.cornerRadius : crossPoint.y;
          crossPoint.y =  crossPoint.y > (textBottom - opts.spikeGirth/2) - opts.cornerRadius ? (textBottom - opts.spikeGirth/2) - opts.cornerRadius : crossPoint.y;
          points[points.length] = {x: textLeft, y: crossPoint.y - opts.spikeGirth/2, type: 'join'};
          points[points.length] = {x: textLeft, y: textTop, type: 'corner'};     // left top corner
          points[points.length] = {x: textRight, y: textTop, type: 'corner'};    // right top corner
          points[points.length] = {x: textRight, y: textBottom, type: 'corner'}; // right bottom corner
          points[points.length] = {x: textLeft, y: textBottom, type: 'corner'};  // left bottom corner
          points[points.length] = {x: textLeft, y: crossPoint.y + opts.spikeGirth/2, type: 'join'};
          points[points.length] = spikePoint;
          break;
      } // </ switch >

      var canvas = $('<canvas width="'+ (numb($text.outerWidth(true)) + opts.strokeWidth*2) +'" height="'+ (numb($text.outerHeight(true)) + opts.strokeWidth*2) +'"></canvas>').appendTo($box).css({position: 'absolute', top: $text.btPosition().top, left: $text.btPosition().left, zIndex: opts.boxzIndex}).get(0);

      // if excanvas is set up, we need to initialize the new canvas element
      if (typeof G_vmlCanvasManager != 'undefined') {
        canvas = G_vmlCanvasManager.initElement(canvas);
      }

      if (opts.cornerRadius > 0) {
        // round the corners!
        var newPoints = new Array();
        var newPoint;
        for (var i=0; i<points.length; i++) {
          if (points[i].type == 'corner') {
            // create two new arc points
            // find point between this and previous (using modulo in case of ending)
            newPoint = betweenPoint(points[i], points[(i-1)%points.length], opts.cornerRadius);
            newPoint.type = 'arcStart';
            newPoints[newPoints.length] = newPoint;
            // the original corner point
            newPoints[newPoints.length] = points[i];
            // find point between this and next
            newPoint = betweenPoint(points[i], points[(i+1)%points.length], opts.cornerRadius);
            newPoint.type = 'arcEnd';
            newPoints[newPoints.length] = newPoint;
          }
          else {
            newPoints[newPoints.length] = points[i];
          }
        }
        // overwrite points with new version
        points = newPoints;

      }

      var ctx = canvas.getContext("2d");
      drawIt.apply(ctx, [points], opts.strokeWidth);
      ctx.fillStyle = opts.fill;
      if (opts.shadow) {
        ctx.shadowOffsetX = 2;
        ctx.shadowOffsetY = 2;
        ctx.shadowBlur = 5;
        ctx.shadowColor =  opts.shadowColor;
      }
      ctx.closePath();
      ctx.fill();
      if (opts.strokeWidth > 0) {
        ctx.shadowColor = 'rgba(0, 0, 0, 0)';
        ctx.lineWidth = opts.strokeWidth;
        ctx.strokeStyle = opts.strokeStyle;
        ctx.beginPath();
        drawIt.apply(ctx, [points], opts.strokeWidth);
        ctx.closePath();
        ctx.stroke();
      }

      if (opts.animate) {
        $box.css({opacity: 0.1});
      }

      $box.css({visibility: 'visible'});

      if (opts.overlay) {
        // EXPERIMENTAL!!!!
        var overlay = $('<div class="bt-overlay"></div>').css({
            position: 'absolute',
            backgroundColor: 'blue',
            top: top,
            left: left,
            width: width,
            height: height,
            opacity: '.2'
          }).appendTo(offsetParent);
        $(this).data('overlay', overlay);
      }

      var animParams = {opacity: 1};
      if (opts.animate) {
        switch (position) {
          case 'top':
            animParams.top = $box.btPosition().top + opts.distance;
            break;
          case 'left':
            animParams.left = $box.btPosition().left + opts.distance;
            break;
          case 'bottom':
            animParams.top = $box.btPosition().top - opts.distance;
            break;
          case 'right':
            animParams.left = $box.btPosition().left - opts.distance;
            break;
        }
        $box.animate(animParams, {duration: opts.speed, easing: opts.easing});
      }
      
      if ((opts.ajaxPath != null && opts.ajaxCache == false) || ajaxTimeout) {
        // if ajaxCache is not enabled or if there was a server timeout,
        // remove the content variable so it will be loaded again from server
        content = false;
      }
      
      // stick this element into the clickAnywhereToClose stack
      if (opts.clickAnywhereToClose) {
        jQuery.bt.vars.clickAnywhereStack.push(this);
        $(document).click(jQuery.bt.docClick);
      }
      
      // stick this element into the closeWhenOthersOpen stack
      if (opts.closeWhenOthersOpen) {
        jQuery.bt.vars.closeWhenOpenStack.push(this);
      }

      // trigger postShow function
      opts.postShow.apply(this);


    }; // </ turnOn() >

    this.btOff = function() {

      // trigger preHide function
      opts.preHide.apply(this);

      var box = $(this).data('bt-box');
      var overlay = $(this).data('bt-overlay');
      if (typeof box == 'object') {
        $(box).remove();
        $(this).removeData('bt-box');
      }
      if (typeof overlay == 'object') {
        $(overlay).remove();
        $(this).removeData('bt-overlay');
      }
      
      // remove this from the stacks
      jQuery.bt.vars.clickAnywhereStack = arrayRemove(jQuery.bt.vars.clickAnywhereStack, this);
      jQuery.bt.vars.closeWhenOpenStack = arrayRemove(jQuery.bt.vars.closeWhenOpenStack, this);

      // trigger postHide function
      opts.postHide.apply(this);
      
      // remove the 'bt-active' and activeClass classes from target
      $(this).removeClass('bt-active ' + opts.activeClass);

    }; // </ turnOff() >

    var refresh = this.btRefresh = function() {
      this.btOff();
      this.btOn();
    };


  }); // </ this.each() >


  function drawIt(points, strokeWidth) {
    this.moveTo(points[0].x, points[0].y);
    for (i=1;i<points.length;i++) {
      if (points[i-1].type == 'arcStart') {
        // if we're creating a rounded corner
        //ctx.arc(round5(points[i].x), round5(points[i].y), points[i].startAngle, points[i].endAngle, opts.cornerRadius, false);
        this.quadraticCurveTo(round5(points[i].x, strokeWidth), round5(points[i].y, strokeWidth), round5(points[(i+1)%points.length].x, strokeWidth), round5(points[(i+1)%points.length].y, strokeWidth));
        i++;
        //ctx.moveTo(round5(points[i].x), round5(points[i].y));
      }
      else {
        this.lineTo(round5(points[i].x, strokeWidth), round5(points[i].y, strokeWidth));
      }
    }
  }; // </ drawIt() >

  /**
   * For odd stroke widths, round to the nearest .5 pixel to avoid antialiasing
   * http://developer.mozilla.org/en/Canvas_tutorial/Applying_styles_and_colors
   */
  function round5(num, strokeWidth) {
    var ret;
    strokeWidth = numb(strokeWidth);
    if (strokeWidth%2) {
      ret = num;
    }
    else {
      ret = Math.round(num - .5) + .5;
    }
    return ret;
  }; // </ round5() >

  /**
   * Ensure that a number is a number... or zero
   */
  function numb(num) {
    return parseInt(num) || 0;
  }; // </ numb() >
  
  /**
   * Remove an element from an array
   */ 
  function arrayRemove(arr, elem) {
    var x, newArr = new Array();
    for (x in arr) {
      if (arr[x] != elem) {
        newArr.push(arr[x]);
      }
    }
    return newArr;
  }; // </ arrayRemove() >

  /**
   * Given two points, find a point which is dist pixels from point1 on a line to point2
   */
  function betweenPoint(point1, point2, dist) {
    // figure out if we're horizontal or vertical
    var y, x;
    if (point1.x == point2.x) {
      // vertical
      y = point1.y < point2.y ? point1.y + dist : point1.y - dist;
      return {x: point1.x, y: y};
    }
    else if (point1.y == point2.y) {
      // horizontal
      x = point1.x < point2.x ? point1.x + dist : point1.x - dist;
      return {x:x, y: point1.y};
    }
  }; // </ betweenPoint() >

  function centerPoint(arcStart, corner, arcEnd) {
    var x = corner.x == arcStart.x ? arcEnd.x : arcStart.x;
    var y = corner.y == arcStart.y ? arcEnd.y : arcStart.y;
    var startAngle, endAngle;
    if (arcStart.x < arcEnd.x) {
      if (arcStart.y > arcEnd.y) {
        // arc is on upper left
        startAngle = (Math.PI/180)*180;
        endAngle = (Math.PI/180)*90;
      }
      else {
        // arc is on upper right
        startAngle = (Math.PI/180)*90;
        endAngle = 0;
      }
    }
    else {
      if (arcStart.y > arcEnd.y) {
        // arc is on lower left
        startAngle = (Math.PI/180)*270;
        endAngle = (Math.PI/180)*180;
      }
      else {
        // arc is on lower right
        startAngle = 0;
        endAngle = (Math.PI/180)*270;
      }
    }
    return {x: x, y: y, type: 'center', startAngle: startAngle, endAngle: endAngle};
  }; // </ centerPoint() >

  /**
   * Find the intersection point of two lines, each defined by two points
   * arguments are x1, y1 and x2, y2 for r1 (line 1) and r2 (line 2)
   * It's like an algebra party!!!
   */
  function findIntersect(r1x1, r1y1, r1x2, r1y2, r2x1, r2y1, r2x2, r2y2) {

    if (r2x1 == r2x2) {
      return findIntersectY(r1x1, r1y1, r1x2, r1y2, r2x1);
    }
    if (r2y1 == r2y2) {
      return findIntersectX(r1x1, r1y1, r1x2, r1y2, r2y1);
    }

    // m = (y1 - y2) / (x1 - x2)  // <-- how to find the slope
    // y = mx + b                 // the 'classic' linear equation
    // b = y - mx                 // how to find b (the y-intersect)
    // x = (y - b)/m              // how to find x
    var r1m = (r1y1 - r1y2) / (r1x1 - r1x2);
    var r1b = r1y1 - (r1m * r1x1);
    var r2m = (r2y1 - r2y2) / (r2x1 - r2x2);
    var r2b = r2y1 - (r2m * r2x1);

    var x = (r2b - r1b) / (r1m - r2m);
	  var y = r1m * x + r1b;

	  return {x: x, y: y};
  }; // </ findIntersect() >

  /**
   * Find the y intersection point of a line and given x vertical
   */
  function findIntersectY(r1x1, r1y1, r1x2, r1y2, x) {
    if (r1y1 == r1y2) {
      return {x: x, y: r1y1};
    }
    var r1m = (r1y1 - r1y2) / (r1x1 - r1x2);
    var r1b = r1y1 - (r1m * r1x1);

    var y = r1m * x + r1b;

    return {x: x, y: y};
  }; // </ findIntersectY() >

  /**
   * Find the x intersection point of a line and given y horizontal
   */
  function findIntersectX(r1x1, r1y1, r1x2, r1y2, y) {
    if (r1x1 == r1x2) {
      return {x: r1x1, y: y};
    }
    var r1m = (r1y1 - r1y2) / (r1x1 - r1x2);
    var r1b = r1y1 - (r1m * r1x1);

    // y = mx + b     // your old friend, linear equation
    // x = (y - b)/m  // linear equation solved for x
    var x = (y - r1b) / r1m;

    return {x: x, y: y};

  }; // </ findIntersectX() >

}; // </ jQuery.fn.bt() >

/**
 * jQuery's compat.js (used in Drupal's jQuery upgrade module, overrides the $().position() function
 *  this is a copy of that function to allow the plugin to work when compat.js is present
 *  once compat.js is fixed to not override existing functions, this function can be removed
 *  and .btPosion() can be replaced with .position() above...
 */
jQuery.fn.btPosition = function() {

  function num(elem, prop) {
    return elem[0] && parseInt( jQuery.curCSS(elem[0], prop, true), 10 ) || 0;
  };

  var left = 0, top = 0, results;

  if ( this[0] ) {
    // Get *real* offsetParent
    var offsetParent = this.offsetParent(),

    // Get correct offsets
    offset       = this.offset(),
    parentOffset = /^body|html$/i.test(offsetParent[0].tagName) ? { top: 0, left: 0 } : offsetParent.offset();

    // Subtract element margins
    // note: when an element has margin: auto the offsetLeft and marginLeft
    // are the same in Safari causing offset.left to incorrectly be 0
    offset.top  -= num( this, 'marginTop' );
    offset.left -= num( this, 'marginLeft' );

    // Add offsetParent borders
    parentOffset.top  += num( offsetParent, 'borderTopWidth' );
    parentOffset.left += num( offsetParent, 'borderLeftWidth' );

    // Subtract the two offsets
    results = {
      top:  offset.top  - parentOffset.top,
      left: offset.left - parentOffset.left
    };
  }

  return results;
}; // </ jQuery.fn.btPosition() >


/**
 * A convenience function to run btOn() (if available)
 * for each selected item
 */
jQuery.fn.btOn = function() {
  return this.each(function(index){
    if ($.isFunction(this.btOn)) {
      this.btOn();
    }
  });
}; // </ $().btOn() >

/**
 * 
 * A convenience function to run btOff() (if available)
 * for each selected item
 */
jQuery.fn.btOff = function() {
  return this.each(function(index){
    if ($.isFunction(this.btOff)) {
      this.btOff();
    }
  });
}; // </ $().btOff() >

jQuery.bt = {};
jQuery.bt.vars = {clickAnywhereStack: [], closeWhenOpenStack: []};

/**
 * This function gets bound to the document's click event
 * It turns off all of the tips in the click-anywhere-to-close stack
 */
jQuery.bt.docClick = function(e) {
  if (!e) {
    var e = window.event;
  };  
  if (!$(e.target).parents().andSelf().filter('.bt-wrapper, .bt-active').length) {
    // if clicked element isn't inside tip, close tips in stack
    $(jQuery.bt.vars.clickAnywhereStack).btOff();
    $(document).unbind('click', jQuery.bt.docClick);
  }
}; // </ docClick() >

/**
 * Defaults for the beauty tips
 *
 * Note this is a variable definition and not a function. So defaults can be
 * written for an entire page by simply redefining attributes like so:
 *
 *   jQuery.bt.defaults.width = 400;
 *
 * This would make all Beauty Tips boxes 400px wide.
 *
 * Each of these options may also be overridden during
 *
 * Can be overriden globally or at time of call.
 *
 */
jQuery.bt.defaults = {
  trigger:         'hover',                // trigger to show/hide tip
                                           // use [on, off] to define separate on/off triggers
                                           // also use space character to allow multiple  to trigger
                                           // examples:
                                           //   ['focus', 'blur'] // focus displays, blur hides
                                           //   'dblclick'        // dblclick toggles on/off
                                           //   ['focus mouseover', 'blur mouseout'] // multiple triggers
                                           //   'now'             // shows/hides tip without event
                                           //   'none'            // use $('#selector').btOn(); and ...btOff();
                                           //   'hoverIntent'     // hover using hoverIntent plugin (settings below)
                                           // note:
                                           //   hoverIntent becomes default if available
                                           
  clickAnywhereToClose: true,              // clicking anywhere outside of the tip will close it 
  closeWhenOthersOpen: false,              // tip will be closed before another opens - stop >= 2 tips being on
                                           
  width:            '200px',               // width of tooltip box
                                           //   when combined with cssStyles: {width: 'auto'}, this becomes a max-width for the text
  padding:          '10px',                // padding for content (get more fine grained with cssStyles)
  spikeGirth:       10,                    // width of spike
  spikeLength:      15,                    // length of spike
  overlap:          0,                     // spike overlap (px) onto target (can cause problems with 'hover' trigger)
  overlay:          false,                 // display overlay on target (use CSS to style) -- BUGGY!
  killTitle:        true,                  // kill title tags to avoid double tooltips

  textzIndex:       9999,                  // z-index for the text
  boxzIndex:        9998,                  // z-index for the "talk" box (should always be less than textzIndex)
  wrapperzIndex:    9997,
  positions:        ['top'],              // preference of positions for tip (will use first with available space)
                                           // possible values 'top', 'bottom', 'left', 'right' as an array in order of
                                           // preference. Last value will be used if others don't have enough space.
                                           // or use 'most' to use the area with the most space
  fill:             "rgb(130, 165, 240)",  // fill color for the tooltip box
  
  windowMargin:     10,                    // space (px) to leave between text box and browser edge

  strokeWidth:      1,                     // width of stroke around box, **set to 0 for no stroke**
  strokeStyle:      "#000",                // color/alpha of stroke

  cornerRadius:     5,                     // radius of corners (px), set to 0 for square corners
  
                    // following values are on a scale of 0 to 1 with .5 being centered
  
  centerPointX:     .5,                    // the spike extends from center of the target edge to this point
  centerPointY:     .5,                    // defined by percentage horizontal (x) and vertical (y)
    
  shadow:           false,                 // use drop shadow? (only displays in Safari and FF 3.1) - experimental
  shadowOffsetX:    2,                     // shadow offset x (px)
  shadowOffsetY:    2,                     // shadow offset y (px)
  shadowBlur:       3,                     // shadow blur (px)
  shadowColor:      "#000",                // shadow color/alpha

  animate:          false,                 // animate show/hide of box - EXPERIMENTAL (buggy in IE)
  distance:         15,                    // distance of animation movement (px)
  easing:           'swing',               // animation easing
  speed:            200,                   // speed (ms) of animation

  cssClass:         '',                    // CSS class to add to the box wrapper div (of the TIP)
  cssStyles:        {},                    // styles to add the text box
                                           //   example: {fontFamily: 'Georgia, Times, serif', fontWeight: 'bold'}
                                               
  activeClass:      'bt-active',           // class added to TARGET element when its BeautyTip is active

  contentSelector:  "$(this).attr('title')", // if there is no content argument, use this selector to retrieve the title

  ajaxPath:         null,                  // if using ajax request for content, this contains url and (opt) selector
                                           // this will override content and contentSelector
                                           // examples (see jQuery load() function):
                                           //   '/demo.html'
                                           //   '/help/ajax/snip'
                                           //   '/help/existing/full div#content'
                                           
                                           // ajaxPath can also be defined as an array
                                           // in which case, the first value will be parsed as a jQuery selector
                                           // the result of which will be used as the ajaxPath
                                           // the second (optional) value is the content selector as above
                                           // examples:
                                           //    ["$(this).attr('href')", 'div#content']
                                           //    ["$(this).parents('.wrapper').find('.title').attr('href')"]
                                           //    ["$('#some-element').val()"]
                                           
  ajaxError:        '<strong>ERROR:</strong> <em>%error</em>',
                                           // error text, use "%error" to insert error from server
  ajaxLoading:     '<blink>Loading...</blink>',  // yes folks, it's the blink tag!
  ajaxData:         {},                    // key/value pairs
  ajaxType:         'GET',                 // 'GET' or 'POST'
  ajaxCache:        true,                  // cache ajax results and do not send request to same url multiple times
  ajaxOpts:         {},                    // any other ajax options - timeout, passwords, processing functions, etc...
                                           // see http://docs.jquery.com/Ajax/jQuery.ajax#options
                                    
  preShow:          function(){return;},       // function to run before popup is built and displayed
  postShow:         function(){return;},       // function to run after popup is built and displayed
  preHide:          function(){return;},       // function to run before popup is removed
  postHide:         function(){return;},       // function to run after popup is removed
  
  hoverIntentOpts:  {                          // options for hoverIntent (if installed)
                      interval: 300,           // http://cherne.net/brian/resources/jquery.hoverIntent.html
                      timeout: 500
                    }
                                               
}; // </ jQuery.bt.defaults >


// @todo
// use larger canvas (extend to edge of page when windowMargin is active)
// add options to shift position of tip vert/horiz and position of spike tip
// create drawn (canvas) shadows
// use overlay to allow overlap with hover
// experiment with making tooltip a subelement of the target
// rework animation system
// ----------------------------------------------------------------------------
// markItUp! Universal MarkUp Engine, JQuery plugin
// v 1.1.5
// Dual licensed under the MIT and GPL licenses.
// ----------------------------------------------------------------------------
// Copyright (C) 2007-2008 Jay Salvat
// http://markitup.jaysalvat.com/
// ----------------------------------------------------------------------------
// 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($) {
	$.fn.markItUp = function(settings, extraSettings) {
		var options, ctrlKey, shiftKey, altKey;
		ctrlKey = shiftKey = altKey = false;

		options = {	id:						'',
					nameSpace:				'',
					root:					'',
					previewInWindow:		'', // 'width=800, height=600, resizable=yes, scrollbars=yes'
					previewAutoRefresh:		true,
					previewPosition:		'after',
					previewTemplatePath:	'~/templates/preview.html',
					previewParserPath:		'',
					previewParserVar:		'data',
					resizeHandle:			true,
					beforeInsert:			'',
					afterInsert:			'',
					onEnter:				{},
					onShiftEnter:			{},
					onCtrlEnter:			{},
					onTab:					{},
					markupSet:			[	{ /* set */ } ]
				};
		$.extend(options, settings, extraSettings);

		// compute markItUp! path
		if (!options.root) {
			$('script').each(function(a, tag) {
				miuScript = $(tag).get(0).src.match(/(.*)jquery\.markitup(\.pack)?\.js$/);
				if (miuScript !== null) {
					options.root = miuScript[1];
				}
			});
		}

		return this.each(function() {
			var $$, textarea, levels, scrollPosition, caretPosition, caretOffset,
				clicked, hash, header, footer, previewWindow, template, iFrame, abort;
			$$ = $(this);
			textarea = this;
			levels = [];
			abort = false;
			scrollPosition = caretPosition = 0;
			caretOffset = -1;

			options.previewParserPath = localize(options.previewParserPath);
			options.previewTemplatePath = localize(options.previewTemplatePath);

			// apply the computed path to ~/
			function localize(data, inText) {
				if (inText) {
					return 	data.replace(/("|')~\//g, "$1"+options.root);
				}
				return 	data.replace(/^~\//, options.root);
			}

			// init and build editor
			function init() {
				id = ''; nameSpace = '';
				if (options.id) {
					id = 'id="'+options.id+'"';
				} else if ($$.attr("id")) {
					id = 'id="markItUp'+($$.attr("id").substr(0, 1).toUpperCase())+($$.attr("id").substr(1))+'"';

				}
				if (options.nameSpace) {
					nameSpace = 'class="'+options.nameSpace+'"';
				}
				$$.wrap('<div '+nameSpace+'></div>');
				$$.wrap('<div '+id+' class="markItUp"></div>');
				$$.wrap('<div class="markItUpContainer"></div>');
				$$.addClass("markItUpEditor");

				// add the header before the textarea
				header = $('<div class="markItUpHeader"></div>').insertBefore($$);
				$(dropMenus(options.markupSet)).appendTo(header);

				// add the footer after the textarea
				footer = $('<div class="markItUpFooter"></div>').insertAfter($$);

				// add the resize handle after textarea
				if (options.resizeHandle === true && $.browser.safari !== true) {
					resizeHandle = $('<div class="markItUpResizeHandle"></div>')
						.insertAfter($$)
						.bind("mousedown", function(e) {
							var h = $$.height(), y = e.clientY, mouseMove, mouseUp;
							mouseMove = function(e) {
								$$.css("height", Math.max(20, e.clientY+h-y)+"px");
								return false;
							};
							mouseUp = function(e) {
								$("html").unbind("mousemove", mouseMove).unbind("mouseup", mouseUp);
								return false;
							};
							$("html").bind("mousemove", mouseMove).bind("mouseup", mouseUp);
					});
					footer.append(resizeHandle);
				}

				// listen key events
				$$.keydown(keyPressed).keyup(keyPressed);
				
				// bind an event to catch external calls
				$$.bind("insertion", function(e, settings) {
					if (settings.target !== false) {
						get();
					}
					if (textarea === $.markItUp.focused) {
						markup(settings);
					}
				});

				// remember the last focus
				$$.focus(function() {
					$.markItUp.focused = this;
				});
			}

			// recursively build header with dropMenus from markupset
			function dropMenus(markupSet) {
				var ul = $('<ul></ul>'), i = 0;
				$('li:hover > ul', ul).css('display', 'block');
				$.each(markupSet, function() {
					var button = this, t = '', title, li, j;
					title = (button.key) ? (button.name||'')+' [Ctrl+'+button.key+']' : (button.name||'');
					key   = (button.key) ? 'accesskey="'+button.key+'"' : '';
					if (button.separator) {
						li = $('<li class="markItUpSeparator">'+(button.separator||'')+'</li>').appendTo(ul);
					} else {
						i++;
						for (j = levels.length -1; j >= 0; j--) {
							t += levels[j]+"-";
						}
						li = $('<li class="markItUpButton markItUpButton'+t+(i)+' '+(button.className||'')+'"><a href="" '+key+' title="'+title+'">'+(button.name||'')+'</a></li>')
						.bind("contextmenu", function() { // prevent contextmenu on mac and allow ctrl+click
							return false;
						}).click(function() {
							return false;
						}).mouseup(function() {
							if (button.call) {
								eval(button.call)();
							}
							markup(button);
							return false;
						}).hover(function() {
								$('> ul', this).show();
								$(document).one('click', function() { // close dropmenu if click outside
										$('ul ul', header).hide();
									}
								);
							}, function() {
								$('> ul', this).hide();
							}
						).appendTo(ul);
						if (button.dropMenu) {
							levels.push(i);
							$(li).addClass('markItUpDropMenu').append(dropMenus(button.dropMenu));
						}
					}
				}); 
				levels.pop();
				return ul;
			}

			// markItUp! markups
			function magicMarkups(string) {
				if (string) {
					string = string.toString();
					string = string.replace(/\(\!\(([\s\S]*?)\)\!\)/g,
						function(x, a) {
							var b = a.split('|!|');
							if (altKey === true) {
								return (b[1] !== undefined) ? b[1] : b[0];
							} else {
								return (b[1] === undefined) ? "" : b[0];
							}
						}
					);
					// [![prompt]!], [![prompt:!:value]!]
					string = string.replace(/\[\!\[([\s\S]*?)\]\!\]/g,
						function(x, a) {
							var b = a.split(':!:');
							if (abort === true) {
								return false;
							}
							value = prompt(b[0], (b[1]) ? b[1] : '');
							if (value === null) {
								abort = true;
							}
							return value;
						}
					);
					return string;
				}
				return "";
			}

			// prepare action
			function prepare(action) {
				if ($.isFunction(action)) {
					action = action(hash);
				}
				return magicMarkups(action);
			}

			// build block to insert
			function build(string) {
				openWith 	= prepare(clicked.openWith);
				placeHolder = prepare(clicked.placeHolder);
				replaceWith = prepare(clicked.replaceWith);
				closeWith 	= prepare(clicked.closeWith);
				if (replaceWith !== "") {
					block = openWith + replaceWith + closeWith;
				} else if (selection === '' && placeHolder !== '') {
					block = openWith + placeHolder + closeWith;
				} else {
					block = openWith + (string||selection) + closeWith;
				}
				return {	block:block, 
							openWith:openWith, 
							replaceWith:replaceWith, 
							placeHolder:placeHolder,
							closeWith:closeWith
					};
			}

			// define markup to insert
			function markup(button) {
				var len, j, n, i;
				hash = clicked = button;
				get();

				$.extend(hash, {	line:"", 
						 			root:options.root,
									textarea:textarea, 
									selection:(selection||''), 
									caretPosition:caretPosition,
									ctrlKey:ctrlKey, 
									shiftKey:shiftKey, 
									altKey:altKey
								}
							);
				// callbacks before insertion
				prepare(options.beforeInsert);
				prepare(clicked.beforeInsert);
				if (ctrlKey === true && shiftKey === true) {
					prepare(clicked.beforeMultiInsert);
				}			
				$.extend(hash, { line:1 });
				
				if (ctrlKey === true && shiftKey === true) {
					lines = selection.split(/\r?\n/);
					for (j = 0, n = lines.length, i = 0; i < n; i++) {
						if ($.trim(lines[i]) !== '') {
							$.extend(hash, { line:++j, selection:lines[i] } );
							lines[i] = build(lines[i]).block;
						} else {
							lines[i] = "";
						}
					}
					string = { block:lines.join('\n')};
					start = caretPosition;
					len = string.block.length + (($.browser.opera) ? n : 0);
				} else if (ctrlKey === true) {
					string = build(selection);
					start = caretPosition + string.openWith.length;
					len = string.block.length - string.openWith.length - string.closeWith.length;
					len -= fixIeBug(string.block);
				} else if (shiftKey === true) {
					string = build(selection);
					start = caretPosition;
					len = string.block.length;
					len -= fixIeBug(string.block);
				} else {
					string = build(selection);
					start = caretPosition + string.block.length ;
					len = 0;
					start -= fixIeBug(string.block);
				}
				if ((selection === '' && string.replaceWith === '')) {
					caretOffset += fixOperaBug(string.block);
					
					start = caretPosition + string.openWith.length;
					len = string.block.length - string.openWith.length - string.closeWith.length;

					caretOffset = $$.val().substring(caretPosition,  $$.val().length).length;
					caretOffset -= fixOperaBug($$.val().substring(0, caretPosition));
				}
				$.extend(hash, { caretPosition:caretPosition, scrollPosition:scrollPosition } );

				if (string.block !== selection && abort === false) {
					insert(string.block);
					set(start, len);
				} else {
					caretOffset = -1;
				}
				get();

				$.extend(hash, { line:'', selection:selection });

				// callbacks after insertion
				if (ctrlKey === true && shiftKey === true) {
					prepare(clicked.afterMultiInsert);
				}
				prepare(clicked.afterInsert);
				prepare(options.afterInsert);

				// refresh preview if opened
				if (previewWindow && options.previewAutoRefresh) {
					refreshPreview(); 
				}
																									
				// reinit keyevent
				shiftKey = altKey = ctrlKey = abort = false;
			}

			// Substract linefeed in Opera
			function fixOperaBug(string) {
				if ($.browser.opera) {
					return string.length - string.replace(/\n*/g, '').length;
				}
				return 0;
			}
			// Substract linefeed in IE
			function fixIeBug(string) {
				if ($.browser.msie) {
					return string.length - string.replace(/\r*/g, '').length;
				}
				return 0;
			}
				
			// add markup
			function insert(block) {	
				if (document.selection) {
					var newSelection = document.selection.createRange();
					newSelection.text = block;
				} else {
					$$.val($$.val().substring(0, caretPosition)	+ block + $$.val().substring(caretPosition + selection.length, $$.val().length));
				}
			}

			// set a selection
			function set(start, len) {
				if (textarea.createTextRange){
					// quick fix to make it work on Opera 9.5
					if ($.browser.opera && $.browser.version >= 9.5 && len == 0) {
						return false;
					}
					range = textarea.createTextRange();
					range.collapse(true);
					range.moveStart('character', start); 
					range.moveEnd('character', len); 
					range.select();
				} else if (textarea.setSelectionRange ){
					textarea.setSelectionRange(start, start + len);
				}
				textarea.scrollTop = scrollPosition;
				textarea.focus();
			}

			// get the selection
			function get() {
				textarea.focus();

				scrollPosition = textarea.scrollTop;
				if (document.selection) {
					selection = document.selection.createRange().text;
					if ($.browser.msie) { // ie
						var range = document.selection.createRange(), rangeCopy = range.duplicate();
						rangeCopy.moveToElementText(textarea);
						caretPosition = -1;
						while(rangeCopy.inRange(range)) { // fix most of the ie bugs with linefeeds...
							rangeCopy.moveStart('character');
							caretPosition ++;
						}
					} else { // opera
						caretPosition = textarea.selectionStart;
					}
				} else { // gecko
					caretPosition = textarea.selectionStart;
					selection = $$.val().substring(caretPosition, textarea.selectionEnd);
				} 
				return selection;
			}

			// open preview window
			function preview() {
				if (!previewWindow || previewWindow.closed) {
					if (options.previewInWindow) {
						previewWindow = window.open('', 'preview', options.previewInWindow);
					} else {
						iFrame = $('<iframe class="markItUpPreviewFrame"></iframe>');
						if (options.previewPosition == 'after') {
							iFrame.insertAfter(footer);
						} else {
							iFrame.insertBefore(header);
						}	
						previewWindow = iFrame[iFrame.length-1].contentWindow || frame[iFrame.length-1];
					}
				} else if (altKey === true) {
					if (iFrame) {
						iFrame.remove();
					}
					previewWindow.close();
					previewWindow = iFrame = false;
				}
				if (!options.previewAutoRefresh) {
					refreshPreview(); 
				}
			}

			// refresh Preview window
			function refreshPreview() {
				if (previewWindow.document) {			
					try {
						sp = previewWindow.document.documentElement.scrollTop
					} catch(e) {
						sp = 0;
					}					
					previewWindow.document.open();
					previewWindow.document.write(renderPreview());
					previewWindow.document.close();
					previewWindow.document.documentElement.scrollTop = sp;
				}
				if (options.previewInWindow) {
					previewWindow.focus();
				}
			}

			function renderPreview() {				
				if (options.previewParserPath !== '') {
					$.ajax( {
						type: 'POST',
						async: false,
						url: options.previewParserPath,
						data: options.previewParserVar+'='+encodeURIComponent($$.val()),
						success: function(data) {
							phtml = localize(data, 1); 
						}
					} );
				} else {
					if (!template) {
						$.ajax( {
							async: false,
							url: options.previewTemplatePath,
							success: function(data) {
								template = localize(data, 1); 
							}
						} );
					}
					phtml = template.replace(/<!-- content -->/g, $$.val());
				}
				return phtml;
			}
			
			// set keys pressed
			function keyPressed(e) { 
				shiftKey = e.shiftKey;
				altKey = e.altKey;
				ctrlKey = (!(e.altKey && e.ctrlKey)) ? e.ctrlKey : false;

				if (e.type === 'keydown') {
					if (ctrlKey === true) {
						li = $("a[accesskey="+String.fromCharCode(e.keyCode)+"]", header).parent('li');
						if (li.length !== 0) {
							ctrlKey = false;
							li.triggerHandler('mouseup');
							return false;
						}
					}
					if (e.keyCode === 13 || e.keyCode === 10) { // Enter key
						if (ctrlKey === true) {  // Enter + Ctrl
							ctrlKey = false;
							markup(options.onCtrlEnter);
							return options.onCtrlEnter.keepDefault;
						} else if (shiftKey === true) { // Enter + Shift
							shiftKey = false;
							markup(options.onShiftEnter);
							return options.onShiftEnter.keepDefault;
						} else { // only Enter
							markup(options.onEnter);
							return options.onEnter.keepDefault;
						}
					}
					if (e.keyCode === 9) { // Tab key
						if (shiftKey == true || ctrlKey == true || altKey == true) { // Thx Dr Floob.
							return false; 
						}
						if (caretOffset !== -1) {
							get();
							caretOffset = $$.val().length - caretOffset;
							set(caretOffset, 0);
							caretOffset = -1;
							return false;
						} else {
							markup(options.onTab);
							return options.onTab.keepDefault;
						}
					}
				}
			}

			init();
		});
	};

	$.fn.markItUpRemove = function() {
		return this.each(function() {
				$$ = $(this).unbind().removeClass('markItUpEditor');
				$$.parent('div').parent('div.markItUp').parent('div').replaceWith($$);
			}
		);
	};

	$.markItUp = function(settings) {
		var options = { target:false };
		$.extend(options, settings);
		if (options.target) {
			return $(options.target).each(function() {
				$(this).focus();
				$(this).trigger('insertion', [options]);
			});
		} else {
			$('textarea').trigger('insertion', [options]);
		}
	};
})(jQuery);
/*
 * jQuery Menu plugin
 * Version: 0.0.9
 *
 * Copyright (c) 2007 Roman Weich
 * http://p.sohei.org
 *
 * Dual licensed under the MIT and GPL licenses 
 * (This means that you can choose the license that best suits your project, and use it accordingly):
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Changelog: 
 * v 0.0.9 - 2008-01-19
 */

(function($)
{
	var menus = [], //list of all menus
		visibleMenus = [], //list of all visible menus
		activeMenu = activeItem = null,
		menuDIVElement = $('<div class="menu-div outerbox" style="position:absolute;top:0;left:0;display:none;"><div class="shadowbox1"></div><div class="shadowbox2"></div><div class="shadowbox3"></div></div>')[0],
		menuULElement = $('<ul class="menu-ul innerbox"></ul>')[0],
		menuItemElement = $('<li style="position:relative;"><div class="menu-item"></div></li>')[0],
		arrowElement = $('<img class="menu-item-arrow" />')[0],
		$rootDiv = $('<div id="root-menu-div" style="position:absolute;top:0;left:0;"></div>'), //create main menu div
		defaults = {
			// $.Menu options
			showDelay : 200,
			hideDelay : 200,
			hoverOpenDelay: 0,
			offsetTop : 0,
			offsetLeft : 0,
			minWidth: 0,
			onOpen: null,
			onClose: null,

			// $.MenuItem options
			onClick: null,
			arrowSrc: null,
			addExpando: false,
			
			// $.fn.menuFromElement options
			copyClassAttr: false
		};
	
	$(function(){
		$rootDiv.appendTo('body');
	});
	
	$.extend({
		MenuCollection : function(items) {
		
			this.menus = [];
		
			this.init(items);
		}
	});
	$.extend($.MenuCollection, {
		prototype : {
			init : function(items)
			{
				if ( items && items.length )
				{
					for ( var i = 0; i < items.length; i++ )
					{
						this.addMenu(items[i]);
						items[i].menuCollection = this;
					}
				}
			},
			addMenu : function(menu)
			{
				if ( menu instanceof $.Menu )
					this.menus.push(menu);
				
				menu.menuCollection = this;
			
				var self = this;
				$(menu.target).hover(function(){
					if ( menu.visible )
						return;

					//when there is an open menu in this collection, hide it and show the new one
					for ( var i = 0; i < self.menus.length; i++ )
					{
						if ( self.menus[i].visible )
						{
							self.menus[i].hide();
							menu.show();
							return;
						}
					}
				}, function(){});
			}
		}
	});

	
	$.extend({
		Menu : function(target, items, options) {
			this.menuItems = []; //all direct child $.MenuItem objects
			this.subMenus = []; //all subMenus from this.menuItems
			this.visible = false;
			this.active = false; //this menu has hover or one of its submenus is open
			this.parentMenuItem = null;
			this.settings = $.extend({}, defaults, options);
			this.target = target;
			this.$eDIV = null;
			this.$eUL = null;
			this.timer = null;
			this.menuCollection = null;
			this.openTimer = null;

			this.init();
			if ( items && items.constructor == Array )
				this.addItems(items);
		}
	});

	$.extend($.Menu, {
		checkMouse : function(e)
		{
			var t = e.target;

			//the user clicked on the target of the currenty open menu
			if ( visibleMenus.length && t == visibleMenus[0].target )
				return;
			
			//get the last node before the #root-menu-div
			while ( t.parentNode && t.parentNode != $rootDiv[0] )
				t = t.parentNode;

			//is the found node one of the visible menu elements?
			if ( !$(visibleMenus).filter(function(){ return this.$eDIV[0] == t }).length )
			{
				$.Menu.closeAll();
			}
		},
		checkKey : function(e)
		{
			switch ( e.keyCode )
			{
				case 13: //return
					if ( activeItem )
						activeItem.click(e, activeItem.$eLI[0]);
					break;
				case 27: //ESC
					$.Menu.closeAll();
					break;
				case 37: //left
					if ( !activeMenu )
						activeMenu = visibleMenus[0];
					var a = activeMenu;
					if ( a && a.parentMenuItem ) //select the parent menu and close the submenu
					{
						//unbind the events temporary, as we dont want the hoverout event to fire
						var pmi = a.parentMenuItem;
						pmi.$eLI.unbind('mouseout').unbind('mouseover');
						a.hide();
						pmi.hoverIn(true);
						setTimeout(function(){ //bind again..but delay it
							pmi.bindHover();
						});
					}
					else if ( a && a.menuCollection ) //select the previous menu in the collection
					{
						var pos,
							mcm = a.menuCollection.menus;
						if ( (pos = $.inArray(a, mcm)) > -1 )
						{
							if ( --pos < 0 )
								pos = mcm.length - 1;
							$.Menu.closeAll();
							mcm[pos].show();
							mcm[pos].setActive();
							if ( mcm[pos].menuItems.length ) //select the first item
								mcm[pos].menuItems[0].hoverIn(true);
						}
					}
					break;
				case 38: //up
					if ( activeMenu )
						activeMenu.selectNextItem(-1);
					break;
				case 39: //right
					if ( !activeMenu )
						activeMenu = visibleMenus[0];
					var m,
						a = activeMenu,
						asm = activeItem ? activeItem.subMenu : null;
					if ( a )
					{
						if ( asm && asm.menuItems.length ) //select the submenu
						{
							asm.show();
							asm.menuItems[0].hoverIn();
						}
						else if ( (a = a.inMenuCollection()) ) //select the next menu in the collection
						{
							var pos,
								mcm = a.menuCollection.menus;
							if ( (pos = $.inArray(a, mcm)) > -1 )
							{
								if ( ++pos >= mcm.length )
									pos = 0;
								$.Menu.closeAll();
								mcm[pos].show();
								mcm[pos].setActive();
								if ( mcm[pos].menuItems.length ) //select the first item
									mcm[pos].menuItems[0].hoverIn(true);
							}
						}
					}
					break;
				case 40: //down
					if ( !activeMenu )
					{
						if ( visibleMenus.length && visibleMenus[0].menuItems.length )
							visibleMenus[0].menuItems[0].hoverIn();
					}
					else
						activeMenu.selectNextItem();
					break;
			}
			if ( e.keyCode > 36 && e.keyCode < 41 )
				return false; //this will prevent scrolling
		},
		closeAll : function()
		{
			while ( visibleMenus.length )
				visibleMenus[0].hide();
		},
		setDefaults : function(d)
		{
			$.extend(defaults, d);
		},
		prototype : {
			/**
			 * create / initialize new menu
			 */
			init : function()
			{
				var self = this;
				if ( !this.target )
					return;
				else if ( this.target instanceof $.MenuItem )
				{
					this.parentMenuItem = this.target;
					this.target.addSubMenu(this);
					this.target = this.target.$eLI;
				}

				menus.push(this);

				//use the dom methods instead the ones from jquery (faster)
				this.$eDIV = $(menuDIVElement.cloneNode(1));
				this.$eUL = $(menuULElement.cloneNode(1));
				this.$eDIV[0].appendChild(this.$eUL[0]);
				$rootDiv[0].appendChild(this.$eDIV[0]);

				//bind events
				if ( !this.parentMenuItem )
				{
					$(this.target).click(function(e){
						self.onClick(e);
					}).hover(function(e){
						self.setActive();

						if ( self.settings.hoverOpenDelay )
						{
							self.openTimer = setTimeout(function(){
								if ( !self.visible )
									self.onClick(e);
							}, self.settings.hoverOpenDelay);
						}
					}, function(){
						if ( !self.visible )
							$(this).removeClass('activetarget');

						if ( self.openTimer )
							clearTimeout(self.openTimer);
					});
				}
				else
				{
					this.$eDIV.hover(function(){
						self.setActive();
					}, function(){});
				}
			},
			setActive : function()
			{
				if ( !this.parentMenuItem )
					$(this.target).addClass('activetarget');
				else
					this.active = true;
			},
			addItem : function(item)
			{
				if ( item instanceof $.MenuItem )
				{
					if ( $.inArray(item, this.menuItems) == -1 )
					{
						this.$eUL.append(item.$eLI);
						this.menuItems.push(item);
						item.parentMenu = this;
						if ( item.subMenu )
							this.subMenus.push(item.subMenu);
					}
				}
				else
				{
					this.addItem(new $.MenuItem(item, this.settings));
				}
			},
			addItems : function(items)
			{
				for ( var i = 0; i < items.length; i++ )
				{
					this.addItem(items[i]);
				}
			},
			removeItem : function(item)
			{
				var pos = $.inArray(item, this.menuItems);
				if ( pos > -1 )
					this.menuItems.splice(pos, 1);
				item.parentMenu = null;
			},
			hide : function()
			{
				if ( !this.visible )
					return;
				
				var i, 
					pos = $.inArray(this, visibleMenus);

				this.$eDIV.hide();

				if ( pos >= 0 )
					visibleMenus.splice(pos, 1);
				this.visible = this.active = false;

				$(this.target).removeClass('activetarget');

				//hide all submenus
				for ( i = 0; i < this.subMenus.length; i++ )
				{
					this.subMenus[i].hide();
				}

				//set all items inactive (e.g. remove hover class..)
				for ( i = 0; i < this.menuItems.length; i++ )
				{
					if ( this.menuItems[i].active )
						this.menuItems[i].setInactive();
				}

				if ( !visibleMenus.length ) //unbind events when the last menu was closed
					$(document).unbind('mousedown', $.Menu.checkMouse).unbind('keydown', $.Menu.checkKey);

				if ( activeMenu == this )
					activeMenu = null;
					
				if ( this.settings.onClose )
					this.settings.onClose.call(this);
			},
			show : function(e)
			{
				if ( this.visible )
					return;

				var zi, 
					pmi = this.parentMenuItem;

				if ( this.menuItems.length ) //show only when it has items
				{
					if ( pmi ) //set z-index
					{
						zi = parseInt(pmi.parentMenu.$eDIV.css('z-index'));
						this.$eDIV.css('z-index', (isNaN(zi) ? 1 : zi + 1));
					}
					this.$eDIV.css({visibility: 'hidden', display:'block'});

					//set min-width
					if ( this.settings.minWidth )
					{
						if ( this.$eDIV.width() < this.settings.minWidth )
							this.$eDIV.css('width', this.settings.minWidth);
					}
					
					this.setPosition();
					this.$eDIV.css({display:'none', visibility: ''}).show();

					//IEs default width: auto is bad! ie6 and ie7 have are producing different errors.. (7 = 5px shadowbox + 2px border)
					if ( $.browser.msie )
						this.$eUL.css('width', parseInt($.browser.version) == 6 ? this.$eDIV.width() - 7 : this.$eUL.width());

					if ( this.settings.onOpen )
						this.settings.onOpen.call(this);
				}
				if ( visibleMenus.length == 0 )
					$(document).bind('mousedown', $.Menu.checkMouse).bind('keydown', $.Menu.checkKey);

				this.visible = true;
				visibleMenus.push(this);
			},
			setPosition : function()
			{
				var $t, o, posX, posY, 
					pmo, //parent menu offset
					wst, //window scroll top
					wsl, //window scroll left
					ww = $(window).width(), 
					wh = $(window).height(),
					pmi = this.parentMenuItem,
					height = this.$eDIV[0].clientHeight,
					width = this.$eDIV[0].clientWidth,
					pheight; //parent height

				if ( pmi )
				{
					//position on the right side of the parent menu item
					o = pmi.$eLI.offset();
					posX = o.left + pmi.$eLI.width();
					posY = o.top;
				}
				else
				{
					//position right below the target
					$t = $(this.target);
					o = $t.offset();
					posX = o.left + this.settings.offsetLeft;
					posY = o.top + $t.height() + this.settings.offsetTop;
				}

				//y-pos
				if ( $.fn.scrollTop )
				{
					wst = $(window).scrollTop();
					if ( wh < height ) //menu is bigger than the window
					{
						//position the menu at the top of the visible area
						posY = wst;
					}
					else if ( wh + wst < posY + height ) //outside on the bottom?
					{
						if ( pmi )
						{
							pmo = pmi.parentMenu.$eDIV.offset();
							pheight = pmi.parentMenu.$eDIV[0].clientHeight;
							if ( height <= pheight )
							{
								//bottom position = parentmenu-bottom position
								posY = pmo.top + pheight - height;
							}
							else
							{
								//top position = parentmenu-top position
								posY = pmo.top;
							}
							//still outside on the bottom?
							if ( wh + wst < posY + height )
							{
								//shift the menu upwards till the bottom is visible
								posY -= posY + height - (wh + wst);
							}
						}
						else
						{
							//shift the menu upwards till the bottom is visible
							posY -= posY + height - (wh + wst);
						}
					}
				}
				//x-pos
				if ( $.fn.scrollLeft )
				{
					wsl = $(window).scrollLeft();
					if ( ww + wsl < posX + width )
					{
						if ( pmi )
						{
							//display the menu not on the right side but on the left side
							posX -= pmi.$eLI.width() + width;
							//outside on the left now?
							if ( posX < wsl )
								posX = wsl;
						}
						else
						{
							//shift the menu to the left until it fits
							posX -= posX + width - (ww + wsl);
						}
					}
				}

				//set position
				this.$eDIV.css({left: posX, top: posY});
			},
			onClick : function(e)
			{
				if ( this.visible )
				{
					this.hide();
					this.setActive(); //the class is removed in the hide() method..add it again
				}
				else
				{
					//close all open menus
					$.Menu.closeAll();
					this.show(e);
				}
			},
			addTimer : function(callback, delay)
			{
				var self = this;
				this.timer = setTimeout(function(){
					callback.call(self);
					self.timer = null;
				}, delay);
			},
			removeTimer : function()
			{
				if ( this.timer )
				{
					clearTimeout(this.timer);
					this.timer = null;
				}
			},
			selectNextItem : function(offset)
			{
				var i, pos = 0,
					mil = this.menuItems.length,
					o = offset || 1;
				
				//get current pos
				for ( i = 0; i < mil; i++ )
				{
					if ( this.menuItems[i].active )
					{
						pos = i;
						break;
					}
				}
				this.menuItems[pos].hoverOut();

				do //jump over the separators
				{
					pos += o;
					if ( pos >= mil )
						pos = 0;
					else if ( pos < 0 )
						pos = mil - 1;
				} while ( this.menuItems[pos].separator );
				this.menuItems[pos].hoverIn(true);
			},
			inMenuCollection : function()
			{
				var m = this;
				while ( m.parentMenuItem )
					m = m.parentMenuItem.parentMenu;
				return m.menuCollection ? m : null;
			},
			destroy : function() //delete menu
			{
				var pos, item;

				this.hide();

				//unbind events
				if ( !this.parentMenuItem )
					$(this.target).unbind('click').unbind('mouseover').unbind('mouseout');
				else
					this.$eDIV.unbind('mouseover').unbind('mouseout');

				//destroy all items
				while ( this.menuItems.length )
				{
					item = this.menuItems[0];
					item.destroy();
					delete item;
				}

				if ( (pos = $.inArray(this, menus)) > -1 )
					menus.splice(pos, 1);

				if ( this.menuCollection )
				{
					if ( (pos = $.inArray(this, this.menuCollection.menus)) > -1 )
						this.menuCollection.menus.splice(pos, 1);
				}
					
				this.$eDIV.remove();
			}
		}
	});

	$.extend({
		MenuItem : function(obj, options)
		{
			if ( typeof obj == 'string' )
				obj = {src: obj};

			this.src = obj.src || '';
			this.url = obj.url || null;
			this.urlTarget = obj.target || null;
			this.addClass = obj.addClass || null;
			this.data = obj.data || null;

			this.$eLI = null;
			this.parentMenu = null;
			this.subMenu = null;
			this.settings = $.extend({}, defaults, options);
			this.active = false;
			this.enabled = true;
			this.separator = false;

			this.init();
			
			if ( obj.subMenu )
				new $.Menu(this, obj.subMenu, options);
		}
	});

	$.extend($.MenuItem, {
		prototype : {
			init : function()
			{
				var i, isStr,
					src = this.src,
					self = this;

				this.$eLI = $(menuItemElement.cloneNode(1));

				if ( this.addClass )
					this.$eLI[0].setAttribute('class', this.addClass);

				if ( this.settings.addExpando && this.data )
					this.$eLI[0].menuData = this.data;
					
				if ( src == '' )
				{
					this.$eLI.addClass('menu-separator');
					this.separator = true;
				}
				else
				{
					isStr = typeof src == 'string';
					if ( isStr && this.url ) //create a link node, when we have an url
						src = $('<a href="' + this.url + '"' + (this.urlTarget ? 'target="' + this.urlTarget + '"' : '') + '>' + src + '</a>');
					else if ( isStr || !src.length )
						src = [src];
					//go through the passed DOM-Elements (or jquery objects or text nodes.) and append them to the menus list item
					//this.$eLI.append(this.src) is really slow when having a lot(!!!) of items
					for ( i = 0; i < src.length; i++ )
					{
						if ( typeof src[i] == 'string' )
						{
							//we cant use createTextNode, as html entities won't be displayed correctly (eg. &copy;)
							elem = document.createElement('span');
							elem.innerHTML = src[i];
							this.$eLI[0].firstChild.appendChild(elem);
						}
						else
							this.$eLI[0].firstChild.appendChild(src[i].cloneNode(1));
					}
				}

				this.$eLI.click(function(e){
					self.click(e, this);
				});
				this.bindHover();
			},
			click : function(e, scope)
			{
				if ( this.enabled && this.settings.onClick )
					this.settings.onClick.call(scope, e, this);
			},
			bindHover : function()
			{
				var self = this;
				this.$eLI.hover(function(){
						self.hoverIn();
					}, function(){
						self.hoverOut();
				});
			},
			hoverIn : function(noSubMenu)
			{
				this.removeTimer();

				var i, 
					pms = this.parentMenu.subMenus,
					pmi = this.parentMenu.menuItems,
					self = this;

				//remove the timer from the parent item, when there is one (e.g. to close the menu)
				if ( this.parentMenu.timer )
					this.parentMenu.removeTimer();

				if ( !this.enabled )
					return;
					
				//deactivate all menuItems on the same level
				for ( i = 0; i < pmi.length; i++ )
				{
					if ( pmi[i].active )
						pmi[i].setInactive();
				}

				this.setActive();
				activeMenu = this.parentMenu;

				//are there open submenus on the same level? close them!
				for ( i = 0; i < pms.length; i++ )
				{
					if ( pms[i].visible && pms[i] != this.subMenu && !pms[i].timer ) //close if there is no closetimer running already
						pms[i].addTimer(function(){
							this.hide();
						}, pms[i].settings.hideDelay);
				}

				if ( this.subMenu && !noSubMenu )
				{
					//set timeout to show menu
					this.subMenu.addTimer(function(){
						this.show();
					}, this.subMenu.settings.showDelay);
				}
			},
			hoverOut : function()
			{
				this.removeTimer();

				if ( !this.enabled )
					return;
				
				if ( !this.subMenu || !this.subMenu.visible )
					this.setInactive();
			},
			removeTimer : function()
			{
				if ( this.subMenu )
				{
					this.subMenu.removeTimer();
				}
			},
			setActive : function()
			{
				this.active = true;
				this.$eLI.addClass('active');

				//set the parent menu item active too if necessary
				var pmi = this.parentMenu.parentMenuItem;
				if ( pmi && !pmi.active )
					pmi.setActive();

				activeItem = this;
			},
			setInactive : function()
			{
				this.active = false;
				this.$eLI.removeClass('active');
				if ( this == activeItem )
					activeItem = null;
			},
			enable : function()
			{
				this.$eLI.removeClass('disabled');
				this.enabled = true;
			},
			disable : function()
			{
				this.$eLI.addClass('disabled');
				this.enabled = false;
			},
			destroy : function()
			{
				this.removeTimer();

				this.$eLI.remove();

				//unbind events
				this.$eLI.unbind('mouseover').unbind('mouseout').unbind('click');
				//delete submenu
				if ( this.subMenu )
				{
					this.subMenu.destroy();
					delete this.subMenu;
				}
				this.parentMenu.removeItem(this);
			},
			addSubMenu : function(menu)
			{
				if ( this.subMenu )
					return;
				this.subMenu = menu;
				if ( this.parentMenu && $.inArray(menu, this.parentMenu.subMenus) == -1 )
					this.parentMenu.subMenus.push(menu);
				if ( this.settings.arrowSrc )
				{
					var a = arrowElement.cloneNode(0);
					a.setAttribute('src', this.settings.arrowSrc);
					this.$eLI[0].firstChild.appendChild(a);
				}
			}
		}
	});
	
	
	$.extend($.fn, {
		menuFromElement : function(options, list, bar)
		{
			var createItems = function(ul)
			{
				var menuItems = [], 
					subItems,
					menuItem,
					lis, $li, i, subUL, submenu, target, 
					classNames = null;

				lis = getAllChilds(ul, 'LI');
				for ( i = 0; i < lis.length; i++ )
				{
					subItems = [];

					if ( !lis[i].childNodes.length ) //empty item? add separator
					{
						menuItems.push(new $.MenuItem('', options));
						continue;
					}

					if ( (subUL = getOneChild(lis[i], 'UL')) )
					{
						subItems = createItems(subUL);
						//remove subUL from DOM
						$(subUL).remove();
					}

					//select the target...get the elements inside the li
					$li = $(lis[i]);
					if ( $li[0].childNodes.length == 1 && $li[0].childNodes[0].nodeType == 3 )
						target = $li[0].childNodes[0].nodeValue;
					else
						target = $li[0].childNodes;

					if ( options && options.copyClassAttr )
						classNames = $li.attr('class');
						
					//create item
					menuItem = new $.MenuItem({src: target, addClass: classNames}, options);
					menuItems.push(menuItem);
					//add submenu
					if ( subItems.length )
						new $.Menu(menuItem, subItems, options);
					
				}
				return menuItems;
			};
			return this.each(function()
			{
				var ul, m;
				//get the list element
				if ( list || (ul = getOneChild(this, 'UL')) )
				{
					//if a specific list element is used, clone it, as we probably need it more than once
					ul = list ? $(list).clone(true)[0] : ul;
					menuItems = createItems(ul);
					if ( menuItems.length )
					{
						m = new $.Menu(this, menuItems, options);
						if ( bar )
							bar.addMenu(m);
					}
					$(ul).hide();
				}
			});
		},
		menuBarFromUL : function(options)
		{
			return this.each(function()
			{
				var i,
					lis = getAllChilds(this, 'LI');

				if ( lis.length )
				{
					bar = new $.MenuCollection();
					for ( i = 0; i < lis.length; i++ )
						$(lis[i]).menuFromElement(options, null, bar);
				}
			});
		},
		menu : function(options, items)
		{
			return this.each(function()
			{
				if ( items && items.constructor == Array )
					new $.Menu(this, items, options);
				else
				{
					if ( this.nodeName.toUpperCase() == 'UL' )
						$(this).menuBarFromUL(options);
					else
						$(this).menuFromElement(options, items);
				}
			});
		}
	});

	//faster than using jquery
	var getOneChild = function(elem, name)
	{
		if ( !elem )
			return null;

		var n = elem.firstChild;
		for ( ; n; n = n.nextSibling ) 
		{
			if ( n.nodeType == 1 && n.nodeName.toUpperCase() == name )
				return n;
		}
		return null;
	};
	//faster than using jquery
	var getAllChilds = function(elem, name)
	{
		if ( !elem )
			return [];

		var r = [],
			n = elem.firstChild;
		for ( ; n; n = n.nextSibling ) 
		{
			if ( n.nodeType == 1 && n.nodeName.toUpperCase() == name )
				r[r.length] = n;
		}
		return r;
	};

})(jQuery);

/*
 * Superfish v1.4.8 - jQuery menu widget
 * Copyright (c) 2008 Joel Birch
 *
 * Dual licensed under the MIT and GPL licenses:
 * 	http://www.opensource.org/licenses/mit-license.php
 * 	http://www.gnu.org/licenses/gpl.html
 *
 * CHANGELOG: http://users.tpg.com.au/j_birch/plugins/superfish/changelog.txt
 */

;(function($){
	$.fn.superfish = function(op){

		var sf = $.fn.superfish,
			c = sf.c,
			$arrow = $(['<span class="',c.arrowClass,'"> &#187;</span>'].join('')),
			over = function(){
				var $$ = $(this), menu = getMenu($$);
				clearTimeout(menu.sfTimer);
				$$.showSuperfishUl().siblings().hideSuperfishUl();
			},
			out = function(){
				var $$ = $(this), menu = getMenu($$), o = sf.op;
				clearTimeout(menu.sfTimer);
				menu.sfTimer=setTimeout(function(){
					o.retainPath=($.inArray($$[0],o.$path)>-1);
					$$.hideSuperfishUl();
					if (o.$path.length && $$.parents(['li.',o.hoverClass].join('')).length<1){over.call(o.$path);}
				},o.delay);	
			},
			getMenu = function($menu){
				var menu = $menu.parents(['ul.',c.menuClass,':first'].join(''))[0];
				sf.op = sf.o[menu.serial];
				return menu;
			},
			addArrow = function($a){ $a.addClass(c.anchorClass).append($arrow.clone()); };
			
		return this.each(function() {
			var s = this.serial = sf.o.length;
			var o = $.extend({},sf.defaults,op);
			o.$path = $('li.'+o.pathClass,this).slice(0,o.pathLevels).each(function(){
				$(this).addClass([o.hoverClass,c.bcClass].join(' '))
					.filter('li:has(ul)').removeClass(o.pathClass);
			});
			sf.o[s] = sf.op = o;
			
			$('li:has(ul)',this)[($.fn.hoverIntent && !o.disableHI) ? 'hoverIntent' : 'hover'](over,out).each(function() {
				if (o.autoArrows) addArrow( $('>a:first-child',this) );
			})
			.not('.'+c.bcClass)
				.hideSuperfishUl();
			
			var $a = $('a',this);
			$a.each(function(i){
				var $li = $a.eq(i).parents('li');
				$a.eq(i).focus(function(){over.call($li);}).blur(function(){out.call($li);});
			});
			o.onInit.call(this);
			
		}).each(function() {
			var menuClasses = [c.menuClass];
			if (sf.op.dropShadows  && !($.browser.msie && $.browser.version < 7)) menuClasses.push(c.shadowClass);
			$(this).addClass(menuClasses.join(' '));
		});
	};

	var sf = $.fn.superfish;
	sf.o = [];
	sf.op = {};
	sf.IE7fix = function(){
		var o = sf.op;
		if ($.browser.msie && $.browser.version > 6 && o.dropShadows && o.animation.opacity!=undefined)
			this.toggleClass(sf.c.shadowClass+'-off');
		};
	sf.c = {
		bcClass     : 'sf-breadcrumb',
		menuClass   : 'sf-js-enabled',
		anchorClass : 'sf-with-ul',
		arrowClass  : 'sf-sub-indicator',
		shadowClass : 'sf-shadow'
	};
	sf.defaults = {
		hoverClass	: 'sfHover',
		pathClass	: 'overideThisToUse',
		pathLevels	: 1,
		delay		: 800,
		animation	: {opacity:'show'},
		speed		: 'normal',
		autoArrows	: true,
		dropShadows : true,
		disableHI	: false,		// true disables hoverIntent detection
		onInit		: function(){}, // callback functions
		onBeforeShow: function(){},
		onShow		: function(){},
		onHide		: function(){}
	};
	$.fn.extend({
		hideSuperfishUl : function(){
			var o = sf.op,
				not = (o.retainPath===true) ? o.$path : '';
			o.retainPath = false;
			var $ul = $(['li.',o.hoverClass].join(''),this).add(this).not(not).removeClass(o.hoverClass)
					.find('>ul').hide().css('visibility','hidden');
			o.onHide.call($ul);
			return this;
		},
		showSuperfishUl : function(){
			var o = sf.op,
				sh = sf.c.shadowClass+'-off',
				$ul = this.addClass(o.hoverClass)
					.find('>ul:hidden').css('visibility','visible');
			sf.IE7fix.call($ul);
			o.onBeforeShow.call($ul);
			$ul.animate(o.animation,o.speed,function(){ sf.IE7fix.call($ul); o.onShow.call($ul); });
			return this;
		}
	});

})(jQuery);

/*
 * Supersubs v0.2b - jQuery plugin
 * Copyright (c) 2008 Joel Birch
 *
 * Dual licensed under the MIT and GPL licenses:
 * 	http://www.opensource.org/licenses/mit-license.php
 * 	http://www.gnu.org/licenses/gpl.html
 *
 *
 * This plugin automatically adjusts submenu widths of suckerfish-style menus to that of
 * their longest list item children. If you use this, please expect bugs and report them
 * to the jQuery Google Group with the word 'Superfish' in the subject line.
 *
 */

;(function($){ // $ will refer to jQuery within this closure

	$.fn.supersubs = function(options){
		var opts = $.extend({}, $.fn.supersubs.defaults, options);
		// return original object to support chaining
		return this.each(function() {
			// cache selections
			var $$ = $(this);
			// support metadata
			var o = $.meta ? $.extend({}, opts, $$.data()) : opts;
			// get the font size of menu.
			// .css('fontSize') returns various results cross-browser, so measure an em dash instead
			var fontsize = $('<li id="menu-fontsize">&#8212;</li>').css({
				'padding' : 0,
				'position' : 'absolute',
				'top' : '-999em',
				'width' : 'auto'
			}).appendTo($$).width(); //clientWidth is faster, but was incorrect here
			// remove em dash
			$('#menu-fontsize').remove();
			// cache all ul elements
			$ULs = $$.find('ul');
			// loop through each ul in menu
			$ULs.each(function(i) {	
				// cache this ul
				var $ul = $ULs.eq(i);
				// get all (li) children of this ul
				var $LIs = $ul.children();
				// get all anchor grand-children
				var $As = $LIs.children('a');
				// force content to one line and save current float property
				var liFloat = $LIs.css('white-space','nowrap').css('float');
				// remove width restrictions and floats so elements remain vertically stacked
				var emWidth = $ul.add($LIs).add($As).css({
					'float' : 'none',
					'width'	: 'auto'
				})
				// this ul will now be shrink-wrapped to longest li due to position:absolute
				// so save its width as ems. Clientwidth is 2 times faster than .width() - thanks Dan Switzer
				.end().end()[0].clientWidth / fontsize;
				// add more width to ensure lines don't turn over at certain sizes in various browsers
				emWidth += o.extraWidth;
				// restrict to at least minWidth and at most maxWidth
				if (emWidth > o.maxWidth)		{ emWidth = o.maxWidth; }
				else if (emWidth < o.minWidth)	{ emWidth = o.minWidth; }
				emWidth += 'em';
				// set ul to width in ems
				$ul.css('width',emWidth);
				// restore li floats to avoid IE bugs
				// set li width to full width of this ul
				// revert white-space to normal
				$LIs.css({
					'float' : liFloat,
					'width' : '100%',
					'white-space' : 'normal'
				})
				// update offset position of descendant ul to reflect new width of parent
				.each(function(){
					var $childUl = $('>ul',this);
					var offsetDirection = $childUl.css('left')!==undefined ? 'left' : 'right';
					$childUl.css(offsetDirection,emWidth);
				});
			});
			
		});
	};
	// expose defaults
	$.fn.supersubs.defaults = {
		minWidth		: 9,		// requires em unit.
		maxWidth		: 25,		// requires em unit.
		extraWidth		: 0			// extra width can ensure lines don't sometimes turn over due to slight browser differences in how they round-off values
	};
	
})(jQuery); // plugin code ends


/**
 * 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/02/08
 *
 * @author Blair Mitchelmore
 * @version 1.1.2
 *
 **/

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.event.special

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 ( var 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);
	});
});



/*

    GalleryView - jQuery Content Gallery Plugin
    Author:         Jack Anderson
    Version:        1.1 (April 5, 2009)
    Documentation:  http://www.spaceforaname.com/jquery/galleryview/
    
    Please use this development script if you intend to make changes to the
    plugin code.  For production sites, please use jquery.galleryview-1.0.1-pack.js.
    
*/
(function($){
    $.fn.galleryView = function(options) {
        var opts = $.extend($.fn.galleryView.defaults,options);
        
        var id;
        var iterator = 0;
        var gallery_width;
        var gallery_height;
        var frame_margin = 10;
        var strip_width;
        var wrapper_width;
        var item_count = 0;
        var slide_method;
        var img_path = '/resources/images/';
        var paused = false;
        var frame_caption_size = 20;
        var frame_margin_top = 5;
        var pointer_width = 2;
        
        //Define jQuery objects for reuse
        var j_gallery;
        var j_filmstrip;
        var j_frames;
        var j_panels;
        var j_pointer;
        
/************************************************/
/*  Plugin Methods                              */
/************************************************/  
        function showItem(i) {
            //Disable next/prev buttons until transition is complete
            $('img.nav-next').unbind('click');
            $('img.nav-prev').unbind('click');
            j_frames.unbind('click');
            if(has_panels) {
                if(opts.fade_panels) {
                    //Fade out all panels and fade in target panel
                    j_panels.fadeOut(opts.transition_speed).eq(i%item_count).fadeIn(opts.transition_speed,function(){
                        if(!has_filmstrip) {
                            $('img.nav-prev').click(showPrevItem);
                            $('img.nav-next').click(showNextItem);      
                        }
                    });
                } 
            }
            
            if(has_filmstrip) {
                //Slide either pointer or filmstrip, depending on transition method
                if(slide_method=='strip') {
                    //Stop filmstrip if it's currently in motion
                    j_filmstrip.stop();
                    
                    //Determine distance between pointer (eventual destination) and target frame
                    var distance = getPos(j_frames[i]).left - (getPos(j_pointer[0]).left+2);
                    var leftstr = (distance>=0?'-=':'+=')+Math.abs(distance)+'px';
                    
                    //Animate filmstrip and slide target frame under pointer
                    //If target frame is a duplicate, jump back to 'original' frame
                    j_filmstrip.animate({
                        'left':leftstr
                    },opts.transition_speed,opts.easing,function(){
                        //Always ensure that there are a sufficient number of hidden frames on either
                        //side of the filmstrip to avoid empty frames
                        if(i>item_count) {
                            i = i%item_count;
                            iterator = i;
                            j_filmstrip.css('left','-'+((opts.frame_width+frame_margin)*i)+'px');
                        } else if (i<=(item_count-strip_size)) {
                            i = (i%item_count)+item_count;
                            iterator = i;
                            j_filmstrip.css('left','-'+((opts.frame_width+frame_margin)*i)+'px');
                        }
                        
                        if(!opts.fade_panels) {
                            j_panels.hide().eq(i%item_count).show();
                        }
                        $('img.nav-prev').click(showPrevItem);
                        $('img.nav-next').click(showNextItem);
                        enableFrameClicking();
                    });
                } else if(slide_method=='pointer') {
                    //Stop pointer if it's currently in motion
                    j_pointer.stop();
                    //Get position of target frame
                    var pos = getPos(j_frames[i]);
                    //Slide the pointer over the target frame
                    j_pointer.animate({
                        'left':(pos.left-2+'px')
                    },opts.transition_speed,opts.easing,function(){ 
                        if(!opts.fade_panels) {
                            j_panels.hide().eq(i%item_count).show();
                        }   
                        $('img.nav-prev').click(showPrevItem);
                        $('img.nav-next').click(showNextItem);
                        enableFrameClicking();
                    });
                }
            
                if($('a',j_frames[i])[0]) {
                    j_pointer.unbind('click').click(function(){
                        var a = $('a',j_frames[i]).eq(0);
                        if(a.attr('target')=='_blank') {window.open(a.attr('href'));}
                        else {location.href = a.attr('href');}
                    });
                }
            }
        };
        function showNextItem() {
            $(document).stopTime("transition");
            if(++iterator==j_frames.length) {iterator=0;}
            showItem(iterator);
            $(document).everyTime(opts.transition_interval,"transition",function(){
                showNextItem();
            });
        };
        function showPrevItem() {
            $(document).stopTime("transition");
            if(--iterator<0) {iterator = item_count-1;}
            //alert(iterator);
            showItem(iterator);
            $(document).everyTime(opts.transition_interval,"transition",function(){
                showNextItem();
            });
        };
        function getPos(el) {
            var left = 0, top = 0;
            var el_id = el.id;
            if(el.offsetParent) {
                do {
                    left += el.offsetLeft;
                    top += el.offsetTop;
                } while(el = el.offsetParent);
            }
            //If we want the position of the gallery itself, return it
            if(el_id == id) {return {'left':left,'top':top};}
            //Otherwise, get position of element relative to gallery
            else {
                var gPos = getPos(j_gallery[0]);
                var gLeft = gPos.left;
                var gTop = gPos.top;
                
                return {'left':left-gLeft,'top':top-gTop};
            }
        };
        function enableFrameClicking() {
            j_frames.each(function(i){
                //If there isn't a link in this frame, set up frame to slide on click
                //Frames with links will handle themselves
                if($('a',this).length==0) {
                    $(this).click(function(){
                        $(document).stopTime("transition");
                        showItem(i);
                        iterator = i;
                        $(document).everyTime(opts.transition_interval,"transition",function(){
                            showNextItem();
                        });
                    });
                }
            });
        };
        
        function buildPanels() {
            //If there are panel captions, add overlay divs
            if($('.panel-overlay').length>0) {j_panels.append('<div class="overlay"></div>');}
            
            if(!has_filmstrip) {
                //Add navigation buttons
                $('<img />').addClass('nav-next').attr('src',img_path+opts.nav_theme+'/next.png').appendTo(j_gallery).css({
                    'position':'absolute',
                    'zIndex':'1100',
                    'cursor':'pointer',
                    'top':((opts.panel_height-22)/2)+'px',
                    'right':'10px',
                    'display':'none'
                }).click(showNextItem);
                $('<img />').addClass('nav-prev').attr('src',img_path+opts.nav_theme+'/prev.png').appendTo(j_gallery).css({
                    'position':'absolute',
                    'zIndex':'1100',
                    'cursor':'pointer',
                    'top':((opts.panel_height-22)/2)+'px',
                    'left':'10px',
                    'display':'none'
                }).click(showPrevItem);
                
                $('<img />').addClass('nav-overlay').attr('src',img_path+opts.nav_theme+'/panel-nav-next.png').appendTo(j_gallery).css({
                    'position':'absolute',
                    'zIndex':'1099',
                    'top':((opts.panel_height-22)/2)-10+'px',
                    'right':'0',
                    'display':'none'
                });
                
                $('<img />').addClass('nav-overlay').attr('src',img_path+opts.nav_theme+'/panel-nav-prev.png').appendTo(j_gallery).css({
                    'position':'absolute',
                    'zIndex':'1099',
                    'top':((opts.panel_height-22)/2)-10+'px',
                    'left':'0',
                    'display':'none'
                });
            }
            j_panels.css({
                'width':(opts.panel_width-parseInt(j_panels.css('paddingLeft').split('px')[0],10)-parseInt(j_panels.css('paddingRight').split('px')[0],10))+'px',
                'height':(opts.panel_height-parseInt(j_panels.css('paddingTop').split('px')[0],10)-parseInt(j_panels.css('paddingBottom').split('px')[0],10))+'px',
                'position':'absolute',
                'top':(opts.filmstrip_position=='top'?(opts.frame_height+frame_margin_top+(opts.show_captions?frame_caption_size:frame_margin_top))+'px':'0px'),
                'left':'0px',
                'overflow':'hidden',
                'background':'black',
                'text-align':'center',
                'display':'none'
            });
            $('.panel-overlay',j_panels).css({
                'position':'absolute',
                'zIndex':'999',
                'width':(opts.panel_width-20)+'px',
                'height':opts.overlay_height+'px',
                'top':(opts.overlay_position=='top'?'0':opts.panel_height-opts.overlay_height+'px'),
                'left':'0',
                'padding':'0 10px',
                'color':opts.overlay_text_color,
                'text-align':'left',
                'fontSize':opts.overlay_font_size
            });
            $('.panel-overlay a',j_panels).css({
                'color':opts.overlay_text_color,
                'textDecoration':'underline',
                'fontWeight':'bold'
            });
            $('.panel-overlay h2',j_panels).css({
                'color':opts.overlay_text_color,
                'fontWeight':'bold'
            });
            $('.overlay',j_panels).css({
                'position':'absolute',
                'zIndex':'998',
                'width':opts.panel_width+'px',
                'height':opts.overlay_height+'px',
                'top':(opts.overlay_position=='top'?'0':opts.panel_height-opts.overlay_height+'px'),
                'left':'0',
                'text-align':'left',
                'background':opts.overlay_color,
                'opacity':opts.overlay_opacity
            });
            $('.panel iframe',j_panels).css({
                'width':opts.panel_width+'px',
                'height':(opts.panel_height-opts.overlay_height)+'px',
                'border':'0'
            });
        };
        
        function buildFilmstrip() {
            //Add wrapper to filmstrip to hide extra frames
            j_filmstrip.wrap('<div class="strip_wrapper"></div>');
            if(slide_method=='strip') {
                j_frames.clone().appendTo(j_filmstrip);
                j_frames.clone().appendTo(j_filmstrip);
                j_frames = $('li',j_filmstrip);
            }
            //If captions are enabled, add caption divs and fill with the image titles
            if(opts.show_captions) {
                j_frames.append('<div class="caption"></div>').each(function(i){
                    $(this).find('.caption').html($(this).find('img').attr('title'));              
                });
            }
            
            j_filmstrip.css({
                'listStyle':'none',
                'margin':'0',
                'padding':'0',
                'width':strip_width+'px',
                'position':'absolute',
                'zIndex':'900',
                'top':'0',
                'left':'0',
                'height':(opts.frame_height+10)+'px',
                'background':opts.background_color
            });
            j_frames.css({
                'float':'left',
                'position':'relative',
                'height':opts.frame_height+'px',
                'zIndex':'901',
                'marginTop':frame_margin_top+'px',
                'marginBottom':'0px',
                'marginRight':frame_margin+'px',
                'padding':'0',
                'cursor':'pointer'
            });
            $('img',j_frames).css({
                'border':'none'
            });
            $('.strip_wrapper',j_gallery).css({
                'position':'absolute',
                'top':(opts.filmstrip_position=='top'?'0px':opts.panel_height+'px'),
                'left':((gallery_width-wrapper_width)/2)+'px',
                'width':wrapper_width+'px',
                'height':(opts.frame_height+frame_margin_top+(opts.show_captions?frame_caption_size:frame_margin_top))+'px',
                'overflow':'hidden'
            });
            $('.caption',j_gallery).css({
                'position':'absolute',
                'top':opts.frame_height+'px',
                'left':'0',
                'margin':'0',
                'width':opts.frame_width+'px',
                'padding':'0',
                'color':opts.caption_text_color,
                'textAlign':'center',
                'fontSize':'10px',
                'height':frame_caption_size+'px',
                
                'lineHeight':frame_caption_size+'px'
            });
            var pointer = $('<div></div>');
            pointer.attr('id','pointer').appendTo(j_gallery).css({
                 'position':'absolute',
                 'zIndex':'1000',
                 'cursor':'pointer',
                 'top':getPos(j_frames[0]).top-(pointer_width/2)+'px',
                 'left':getPos(j_frames[0]).left-(pointer_width/2)+'px',
                 'height':opts.frame_height-pointer_width+'px',
                 'width':opts.frame_width-pointer_width+'px',
                 'margin':'auto',
                 'border':(has_panels?pointer_width+'px solid '+(opts.nav_theme=='dark'?'black':'white'):'none')
            });
            j_pointer = $('#pointer',j_gallery);
            if(has_panels) {
                var pointerArrow = $('<img />');
                pointerArrow.attr('src',img_path+opts.nav_theme+'/pointer'+(opts.filmstrip_position=='top'?'-down':'')+'.png').appendTo($('#pointer')).css({
                    'position':'absolute',
                    'zIndex':'1001',
                    'top':(opts.filmstrip_position=='bottom'?'-'+(10+pointer_width)+'px':opts.frame_height+'px'),
                    'left':((opts.frame_width/2)-10)+'px'
                });
            }
            
            //If the filmstrip is animating, move the strip to the middle third
            if(slide_method=='strip') {
                j_filmstrip.css('left','-'+((opts.frame_width+frame_margin)*item_count)+'px');
                iterator = item_count;
            }
            //If there's a link under the pointer, enable clicking on the pointer
            if($('a',j_frames[iterator])[0]) {
                j_pointer.click(function(){
                    var a = $('a',j_frames[iterator]).eq(0);
                    if(a.attr('target')=='_blank') {window.open(a.attr('href'));}
                    else {location.href = a.attr('href');}
                });
            }
            
            //Add navigation buttons
            $('<img />').addClass('nav-next').attr('src',img_path+opts.nav_theme+'/next.png').appendTo(j_gallery).css({
                'position':'absolute',
                'cursor':'pointer',
                'top':(opts.filmstrip_position=='top'?0:opts.panel_height)+frame_margin_top+((opts.frame_height-22)/2)+'px',
                'right':(gallery_width/2)-(wrapper_width/2)-10-22+'px'
            }).click(showNextItem);
            $('<img />').addClass('nav-prev').attr('src',img_path+opts.nav_theme+'/prev.png').appendTo(j_gallery).css({
                'position':'absolute',
                'cursor':'pointer',
                'top':(opts.filmstrip_position=='top'?0:opts.panel_height)+frame_margin_top+((opts.frame_height-22)/2)+'px',
                'left':(gallery_width/2)-(wrapper_width/2)-10-22+'px'
            }).click(showPrevItem);
        };
        
        //Check mouse to see if it is within the borders of the panel
        //More reliable than 'mouseover' event when elements overlay the panel
        function mouseIsOverPanels(x,y) {       
            var pos = getPos(j_gallery[0]);
            var top = pos.top;
            var left = pos.left;
            return x > left && x < left+opts.panel_width && y > top && y < top+opts.panel_height;               
        };
        
/************************************************/
/*  Main Plugin Code                            */
/************************************************/
        return this.each(function() {
            j_gallery = $(this);
            //Determine path between current page and filmstrip images
            //Scan script tags and look for path to GalleryView plugin
            $('script').each(function(i){
                var s = $(this);
                if(s.attr('src') && s.attr('src').match(/jquery\.galleryview/)){
                    img_path = s.attr('src').split('jquery.galleryview')[0]+'themes/';  
                }
            });
            
            //Hide gallery to prevent Flash of Unstyled Content (FoUC) in IE
            j_gallery.css('visibility','hidden');
            
            //Assign elements to variables for reuse
            j_filmstrip = $('.filmstrip',j_gallery);
            j_frames = $('li',j_filmstrip);
            j_panels = $('.panel',j_gallery);
            
            id = j_gallery.attr('id');
            
            has_panels = j_panels.length > 0;
            has_filmstrip = j_frames.length > 0;
            
            if(!has_panels) opts.panel_height = 0;
            
            //Number of frames in filmstrip
            item_count = has_panels?j_panels.length:j_frames.length;
            
            //Number of frames that can display within the screen's width
            //64 = width of block for navigation button * 2
            //5 = minimum frame margin
            strip_size = has_panels?Math.floor((opts.panel_width-64)/(opts.frame_width+frame_margin)):Math.min(item_count,opts.filmstrip_size); 
            
            
            /************************************************/
            /*  Determine transition method for filmstrip   */
            /************************************************/
                    //If more items than strip size, slide filmstrip
                    //Otherwise, slide pointer
                    if(strip_size >= item_count) {
                        slide_method = 'pointer';
                        strip_size = item_count;
                    }
                    else {slide_method = 'strip';}
            
            /************************************************/
            /*  Determine dimensions of various elements    */
            /************************************************/
                    
                    //Width of gallery block
                    gallery_width = has_panels?opts.panel_width:(strip_size*(opts.frame_width+frame_margin))-frame_margin+64;
                    
                    //Height of gallery block = screen + filmstrip + captions (optional)
                    gallery_height = (has_panels?opts.panel_height:0)+(has_filmstrip?opts.frame_height+frame_margin_top+(opts.show_captions?frame_caption_size:frame_margin_top):0);
                    
                    //Width of filmstrip
                    if(slide_method == 'pointer') {strip_width = (opts.frame_width*item_count)+(frame_margin*(item_count));}
                    else {strip_width = (opts.frame_width*item_count*3)+(frame_margin*(item_count*3));}
                    
                    //Width of filmstrip wrapper (to hide overflow)
                    wrapper_width = ((strip_size*opts.frame_width)+((strip_size-1)*frame_margin));
            
            /************************************************/
            /*  Apply CSS Styles                            */
            /************************************************/
                    j_gallery.css({
                        'position':'relative',
                        'margin':'0',
                        'background':opts.background_color,
                        'border':opts.border,
                        'width':gallery_width+'px',
                        'height':gallery_height+'px'
                    });
            
            /************************************************/
            /*  Build filmstrip and/or panels               */
            /************************************************/
                    if(has_filmstrip) {
                        buildFilmstrip();
                    }
                    if(has_panels) {
                        buildPanels();
                    }

            
            /************************************************/
            /*  Add events to various elements              */
            /************************************************/
                    if(has_filmstrip) enableFrameClicking();
                    
                        
                        
                        $().mousemove(function(e){                          
                            if(mouseIsOverPanels(e.pageX,e.pageY)) {
                                if(opts.pause_on_hover) {
                                    $(document).oneTime(500,"animation_pause",function(){
                                        $(document).stopTime("transition");
                                        paused=true;
                                    });
                                }
                                if(has_panels && !has_filmstrip) {
                                    $('.nav-overlay').fadeIn('fast');
                                    $('.nav-next').fadeIn('fast');
                                    $('.nav-prev').fadeIn('fast');
                                }
                            } else {
                                if(opts.pause_on_hover) {
                                    $(document).stopTime("animation_pause");
                                    if(paused) {
                                        $(document).everyTime(opts.transition_interval,"transition",function(){
                                            showNextItem();
                                        });
                                        paused = false;
                                    }
                                }
                                if(has_panels && !has_filmstrip) {
                                    $('.nav-overlay').fadeOut('fast');
                                    $('.nav-next').fadeOut('fast');
                                    $('.nav-prev').fadeOut('fast');
                                }
                            }
                        });
            
            
            /************************************************/
            /*  Initiate Automated Animation                */
            /************************************************/
                    //Show the first panel
                    j_panels.eq(0).show();

                    //If we have more than one item, begin automated transitions
                    if(item_count > 1) {
                        $(document).everyTime(opts.transition_interval,"transition",function(){
                            showNextItem();
                        });
                    }
                    
                    //Make gallery visible now that work is complete
                    j_gallery.css('visibility','visible');
        });
    };
    
    $.fn.galleryView.defaults = {
        panel_width: 400,
        panel_height: 300,
        frame_width: 80,
        frame_height: 80,
        filmstrip_size: 3,
        overlay_height: 70,
        overlay_font_size: '1em',
        transition_speed: 400,
        transition_interval: 6000,
        overlay_opacity: 0.6,
        overlay_color: 'black',
        background_color: 'black',
        overlay_text_color: 'white',
        caption_text_color: 'white',
        border: '1px solid black',
        nav_theme: 'light',
        easing: 'swing',
        filmstrip_position: 'bottom',
        overlay_position: 'bottom',
        show_captions: false,
        fade_panels: true,
        pause_on_hover: false
    };
})(jQuery);
