/**
 * hoverIntent r6 // 2011.02.26 // jQuery 1.5.1+
 * <http://cherne.net/brian/resources/jquery.hoverIntent.html>
 * 
 * @param f
 *          onMouseOver function || An object with configuration options
 * @param g
 *          onMouseOut function || Nothing (use configuration options object)
 * @author Brian Cherne brian(at)cherne(dot)net
 */
(function($) {
  $.fn.hoverIntent = function(f, g) {
    var cfg = {
      sensitivity : 7,
      interval : 100,
      timeout : 0
    };
    cfg = $.extend(cfg, g ? {
      over : f,
      out : g
    } : f);
    var cX, cY, pX, pY;
    var track = function(ev) {
      cX = ev.pageX;
      cY = ev.pageY
    };
    var compare = function(ev, ob) {
      ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
      if ((Math.abs(pX - cX) + Math.abs(pY - cY)) < cfg.sensitivity) {
        $(ob).unbind("mousemove", track);
        ob.hoverIntent_s = 1;
        return cfg.over.apply(ob, [ ev ])
      } else {
        pX = cX;
        pY = cY;
        ob.hoverIntent_t = setTimeout(function() {
          compare(ev, ob)
        }, cfg.interval)
      }
    };
    var delay = function(ev, ob) {
      ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
      ob.hoverIntent_s = 0;
      return cfg.out.apply(ob, [ ev ])
    };
    var handleHover = function(e) {
      var ev = jQuery.extend({}, e);
      var ob = this;
      if (ob.hoverIntent_t) {
        ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t)
      }
      if (e.type == "mouseenter") {
        pX = ev.pageX;
        pY = ev.pageY;
        $(ob).bind("mousemove", track);
        if (ob.hoverIntent_s != 1) {
          ob.hoverIntent_t = setTimeout(function() {
            compare(ev, ob)
          }, cfg.interval)
        }
      } else {
        $(ob).unbind("mousemove", track);
        if (ob.hoverIntent_s == 1) {
          ob.hoverIntent_t = setTimeout(function() {
            delay(ev, ob)
          }, cfg.timeout)
        }
      }
    };
    return this.bind('mouseenter', handleHover).bind('mouseleave', handleHover)
  }
})(jQuery);

/*
 * jQuery Address Plugin v1.4
 * http://www.asual.com/jquery/address/
 *
 * Copyright (c) 2009-2010 Rostislav Hristov
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * Date: 2011-05-04 14:22:12 +0300 (Wed, 04 May 2011)
 */
(function ($) {

  $.address = (function () {

    var _trigger = function(name) {
        $($.address).trigger(
          $.extend($.Event(name), 
            (function() {
              var parameters = {},
                parameterNames = $.address.parameterNames();
              for (var i = 0, l = parameterNames.length; i < l; i++) {
                parameters[parameterNames[i]] = $.address.parameter(parameterNames[i]);
              }
              return {
                value: $.address.value(),
                path: $.address.path(),
                pathNames: $.address.pathNames(),
                parameterNames: parameterNames,
                parameters: parameters,
                queryString: $.address.queryString()
              };
            }).call($.address)
          )
        );
      },
      _bind = function(value, data, fn) {
        $().bind.apply($($.address), Array.prototype.slice.call(arguments));
        return $.address;
      },
      _supportsState = function() {
        return (_h.pushState && _opts.state !== UNDEFINED);
      },
      _hrefState = function() {
        return ('/' + _l.pathname.replace(new RegExp(_opts.state), '') + 
          _l.search + (_hrefHash() ? '#' + _hrefHash() : '')).replace(_re, '/');
      },
      _hrefHash = function() {
        var index = _l.href.indexOf('#');
        return index != -1 ? _crawl(_l.href.substr(index + 1), FALSE) : '';
      },
      _href = function() {
        return _supportsState() ? _hrefState() : _hrefHash();
      },
      _window = function() {
        try {
          return top.document !== UNDEFINED ? top : window;
        } catch (e) { 
          return window;
        }
      },
      _js = function() {
        return 'javascript';
      },
      _strict = function(value) {
        value = value.toString();
        return (_opts.strict && value.substr(0, 1) != '/' ? '/' : '') + value;
      },
      _crawl = function(value, direction) {
        if (_opts.crawlable && direction) {
          return (value !== '' ? '!' : '') + value;
        }
        return value.replace(/^\!/, '');
      },
      _cssint = function(el, value) {
        return parseInt(el.css(value), 10);
      },
      _search = function(el) {
        var url, s;
        for (var i = 0, l = el.childNodes.length; i < l; i++) {
          try {
            if ('src' in el.childNodes[i] && el.childNodes[i].src) {
              url = String(el.childNodes[i].src);
            }
          } catch (e) {
            // IE Invalid pointer problem with base64 encoded images
          }
          s = _search(el.childNodes[i]);
          if (s) {
            url = s;
          }
        }
        return url;
      },
      _listen = function() {
        if (!_silent) {
          var hash = _href(),
            diff = _value != hash;
          if (diff) {
            if (_msie && _version < 7) {
              _l.reload();
            } else {
              if (_msie && _version < 8 && _opts.history) {
                _st(_html, 50);
              }
              _value = hash;
              _update(FALSE);
            }
          }
        }
      },
      _update = function(internal) {
        _trigger(CHANGE);
        _trigger(internal ? INTERNAL_CHANGE : EXTERNAL_CHANGE);
        _st(_track, 10);
      },
      _track = function() {
        if (_opts.tracker !== 'null' && _opts.tracker !== null) {
          var fn = $.isFunction(_opts.tracker) ? _opts.tracker : _t[_opts.tracker],
            value = (_l.pathname + _l.search + 
                ($.address && !_supportsState() ? $.address.value() : ''))
                .replace(/\/\//, '/').replace(/^\/$/, '');
          if ($.isFunction(fn)) {
            fn(value);
          } else if ($.isFunction(_t.urchinTracker)) {
            _t.urchinTracker(value);
          } else if (_t.pageTracker !== UNDEFINED && $.isFunction(_t.pageTracker._trackPageview)) {
            _t.pageTracker._trackPageview(value);
          } else if (_t._gaq !== UNDEFINED && $.isFunction(_t._gaq.push)) {
            _t._gaq.push(['_trackPageview', decodeURI(value)]);
          }
        }
      },
      _html = function() {
        var src = _js() + ':' + FALSE + ';document.open();document.writeln(\'<html><head><title>' + 
          _d.title.replace('\'', '\\\'') + '</title><script>var ' + ID + ' = "' + encodeURIComponent(_href()) + 
          (_d.domain != _l.hostname ? '";document.domain="' + _d.domain : '') + 
          '";</' + 'script></head></html>\');document.close();';
        if (_version < 7) {
          _frame.src = src;
        } else {
          _frame.contentWindow.location.replace(src);
        }
      },
      _options = function() {
        if (_url && _qi != -1) {
          var param, params = _url.substr(_qi + 1).split('&');
          for (i = 0; i < params.length; i++) {
            param = params[i].split('=');
            if (/^(autoUpdate|crawlable|history|strict|wrap)$/.test(param[0])) {
              _opts[param[0]] = (isNaN(param[1]) ? /^(true|yes)$/i.test(param[1]) : (parseInt(param[1], 10) !== 0));
            }
            if (/^(state|tracker)$/.test(param[0])) {
              _opts[param[0]] = param[1];
            }
          }
          _url = null;
        }
        _value = _href();
      },
      _load = function() {
        if (!_loaded) {
          _loaded = TRUE;
          _options();
          var complete = function() {
              _enable.call(this);
              _unescape.call(this);
            },
            body = $('body').ajaxComplete(complete);
          complete();
          if (_opts.wrap) {
            var wrap = $('body > *')
              .wrapAll('<div style="padding:' + 
                (_cssint(body, 'marginTop') + _cssint(body, 'paddingTop')) + 'px ' + 
                (_cssint(body, 'marginRight') + _cssint(body, 'paddingRight')) + 'px ' + 
                (_cssint(body, 'marginBottom') + _cssint(body, 'paddingBottom')) + 'px ' + 
                (_cssint(body, 'marginLeft') + _cssint(body, 'paddingLeft')) + 'px;" />')
              .parent()
              .wrap('<div id="' + ID + '" style="height:100%;overflow:auto;position:relative;' + 
                (_webkit && !window.statusbar.visible ? 'resize:both;' : '') + '" />');
            $('html, body')
              .css({
                height: '100%',
                margin: 0,
                padding: 0,
                overflow: 'hidden'
              });
            if (_webkit) {
              $('<style type="text/css" />')
                .appendTo('head')
                .text('#' + ID + '::-webkit-resizer { background-color: #fff; }');
            }
          }
          if (_msie && _version < 8) {
            var frameset = _d.getElementsByTagName('frameset')[0];
            _frame = _d.createElement((frameset ? '' : 'i') + 'frame');
            if (frameset) {
              frameset.insertAdjacentElement('beforeEnd', _frame);
              frameset[frameset.cols ? 'cols' : 'rows'] += ',0';
              _frame.noResize = TRUE;
              _frame.frameBorder = _frame.frameSpacing = 0;
            } else {
              _frame.style.display = 'none';
              _frame.style.width = _frame.style.height = 0;
              _frame.tabIndex = -1;
              _d.body.insertAdjacentElement('afterBegin', _frame);
            }
            _st(function() {
              $(_frame).bind('load', function() {
                var win = _frame.contentWindow;
                _value = win[ID] !== UNDEFINED ? win[ID] : '';
                if (_value != _href()) {
                  _update(FALSE);
                  _l.hash = _crawl(_value, TRUE);
                }
              });
              if (_frame.contentWindow[ID] === UNDEFINED) {
                _html();
              }
            }, 50);
          }

          _st(function() {
            _trigger('init');
            _update(FALSE);
          }, 1);

          if (!_supportsState()) {
            if ((_msie && _version > 7) || (!_msie && ('on' + HASH_CHANGE) in _t)) {
              if (_t.addEventListener) {
                _t.addEventListener(HASH_CHANGE, _listen, FALSE);
              } else if (_t.attachEvent) {
                _t.attachEvent('on' + HASH_CHANGE, _listen);
              }
            } else {
              _si(_listen, 50);
            }
          }
        }
      },
      _enable = function() {
        var el, 
          elements = $('a'), 
          length = elements.size(),
          delay = 1,
          index = -1,
          fn = function() {
            if (++index != length) {
              el = $(elements.get(index));
              if (el.is('[rel*="address:"]')) {
                el.address();
              }
              _st(fn, delay);
            }
          };
        _st(fn, delay);
      },
      _popstate = function() {
        if (_value != _href()) {
          _value = _href();
          _update(FALSE);
        }
      },
      _unload = function() {
        if (_t.removeEventListener) {
          _t.removeEventListener(HASH_CHANGE, _listen, FALSE);
        } else if (_t.detachEvent) {
          _t.detachEvent('on' + HASH_CHANGE, _listen);
        }
      },
      _unescape = function() {
        if (_opts.crawlable) {
          var base = _l.pathname.replace(/\/$/, ''),
            fragment = '_escaped_fragment_';
          if ($('body').html().indexOf(fragment) != -1) {
            $('a[href]:not([href^=http]), a[href*="' + document.domain + '"]').each(function() {
              var href = $(this).attr('href').replace(/^http:/, '').replace(new RegExp(base + '/?$'), '');
              if (href === '' || href.indexOf(fragment) != -1) {
                $(this).attr('href', '#' + href.replace(new RegExp('/(.*)\\?' + fragment + '=(.*)$'), '!$2'));
              }
            });
          }
        }
      },
      UNDEFINED,
      ID = 'jQueryAddress',
      STRING = 'string',
      HASH_CHANGE = 'hashchange',
      INIT = 'init',
      CHANGE = 'change',
      INTERNAL_CHANGE = 'internalChange',
      EXTERNAL_CHANGE = 'externalChange',
      TRUE = true,
      FALSE = false,
      _opts = {
        autoUpdate: TRUE, 
        crawlable: FALSE,
        history: TRUE, 
        strict: TRUE,
        wrap: FALSE
      },
      _browser = $.browser, 
      _version = parseFloat($.browser.version),
      _mozilla = _browser.mozilla,
      _msie = _browser.msie,
      _opera = _browser.opera,
      _webkit = _browser.webkit || _browser.safari,
      _supported = FALSE,
      _t = _window(),
      _d = _t.document,
      _h = _t.history, 
      _l = _t.location,
      _si = setInterval,
      _st = setTimeout,
      _re = /\/{2,9}/g,
      _agent = navigator.userAgent,      
      _frame,
      _form,
      _url = _search(document),
      _qi = _url ? _url.indexOf('?') : -1,
      _title = _d.title, 
      _silent = FALSE,
      _loaded = FALSE,
      _justset = TRUE,
      _juststart = TRUE,
      _updating = FALSE,
      _listeners = {}, 
      _value = _href();
      
    if (_msie) {
      _version = parseFloat(_agent.substr(_agent.indexOf('MSIE') + 4));
      if (_d.documentMode && _d.documentMode != _version) {
        _version = _d.documentMode != 8 ? 7 : 8;
      }
      var pc = _d.onpropertychange;
      _d.onpropertychange = function() {
        if (pc) {
          pc.call(_d);
        }
        if (_d.title != _title && _d.title.indexOf('#' + _href()) != -1) {
          _d.title = _title;
        }
      };
    }
    
    _supported = 
      (_mozilla && _version >= 1) || 
      (_msie && _version >= 6) ||
      (_opera && _version >= 9.5) ||
      (_webkit && _version >= 523);
      
    if (_supported) {
      if (_opera) {
        history.navigationMode = 'compatible';
      }
      if (document.readyState == 'complete') {
        var interval = setInterval(function() {
          if ($.address) {
            _load();
            clearInterval(interval);
          }
        }, 50);
      } else {
        _options();
        $(_load);
      }
      $(window).bind('popstate', _popstate).bind('unload', _unload);      
    } else if (!_supported && _hrefHash() !== '') {
      _l.replace(_l.href.substr(0, _l.href.indexOf('#')));
    } else {
      _track();
    }

    return {
      bind: function(type, data, fn) {
        return _bind(type, data, fn);
      },
      init: function(fn) {
        return _bind(INIT, fn);
      },
      change: function(fn) {
        return _bind(CHANGE, fn);
      },
      internalChange: function(fn) {
        return _bind(INTERNAL_CHANGE, fn);
      },
      externalChange: function(fn) {
        return _bind(EXTERNAL_CHANGE, fn);
      },
      baseURL: function() {
        var url = _l.href;
        if (url.indexOf('#') != -1) {
          url = url.substr(0, url.indexOf('#'));
        }
        if (/\/$/.test(url)) {
          url = url.substr(0, url.length - 1);
        }
        return url;
      },
      autoUpdate: function(value) {
        if (value !== UNDEFINED) {
          _opts.autoUpdate = value;
          return this;
        }
        return _opts.autoUpdate;
      },
      crawlable: function(value) {
        if (value !== UNDEFINED) {
          _opts.crawlable = value;
          return this;
        }
        return _opts.crawlable;
      },
      history: function(value) {
        if (value !== UNDEFINED) {
          _opts.history = value;
          return this;
        }
        return _opts.history;
      },
      state: function(value) {
        if (value !== UNDEFINED) {
          _opts.state = value;
          var hrefState = _hrefState();
          if (_opts.state !== UNDEFINED) {
            if (_h.pushState) {
              if (hrefState.substr(0, 3) == '/#/') {
                _l.replace(_opts.state.replace(/^\/$/, '') + hrefState.substr(2));
              }
            } else if (hrefState != '/' && hrefState.replace(/^\/#/, '') != _hrefHash()) {
              _st(function() {
                _l.replace(_opts.state.replace(/^\/$/, '') + '/#' + hrefState);
              }, 1);
            }
          }
          return this;
        }
        return _opts.state;
      },
      strict: function(value) {
        if (value !== UNDEFINED) {
          _opts.strict = value;
          return this;
        }
        return _opts.strict;
      },
      tracker: function(value) {
        if (value !== UNDEFINED) {
          _opts.tracker = value;
          return this;
        }
        return _opts.tracker;
      },
      wrap: function(value) {
        if (value !== UNDEFINED) {
          _opts.wrap = value;
          return this;
        }
        return _opts.wrap;
      },
      update: function() {
        _updating = TRUE;
        this.value(_value);
        _updating = FALSE;
        return this;
      },
      title: function(value) {
        if (value !== UNDEFINED) {
          _st(function() {
            _title = _d.title = value;
            if (_juststart && _frame && _frame.contentWindow && _frame.contentWindow.document) {
              _frame.contentWindow.document.title = value;
              _juststart = FALSE;
            }
            if (!_justset && _mozilla) {
              _l.replace(_l.href.indexOf('#') != -1 ? _l.href : _l.href + '#');
            }
            _justset = FALSE;
          }, 50);
          return this;
        }
        return _d.title;
      },
      value: function(value) {
        if (value !== UNDEFINED) {
          value = _strict(value);
          if (value == '/') {
            value = '';
          }
          if (_value == value && !_updating) {
            return;
          }
          _justset = TRUE;
          _value = value;
          if (_opts.autoUpdate || _updating) {
            _update(TRUE);
            if (_supportsState()) {
              _h[_opts.history ? 'pushState' : 'replaceState']({}, '', 
                  _opts.state.replace(/\/$/, '') + (_value === '' ? '/' : _value));
            } else {
              _silent = TRUE;
              if (_webkit) {
                if (_opts.history) {
                  _l.hash = '#' + _crawl(_value, TRUE);
                } else {
                  _l.replace('#' + _crawl(_value, TRUE));
                }
              } else if (_value != _href()) {
                if (_opts.history) {
                  _l.hash = '#' + _crawl(_value, TRUE);
                } else {
                  _l.replace('#' + _crawl(_value, TRUE));
                }
              }
              if ((_msie && _version < 8) && _opts.history) {
                _st(_html, 50);
              }
              if (_webkit) {
                _st(function(){ _silent = FALSE; }, 1);
              } else {
                _silent = FALSE;
              }
            }
          }
          return this;
        }
        if (!_supported) {
          return null;
        }
        return _strict(_value);
      },
      path: function(value) {
        if (value !== UNDEFINED) {
          var qs = this.queryString(),
            hash = this.hash();
          this.value(value + (qs ? '?' + qs : '') + (hash ? '#' + hash : ''));
          return this;
        }
        return _strict(_value).split('#')[0].split('?')[0];
      },
      pathNames: function() {
        var path = this.path(),
          names = path.replace(_re, '/').split('/');
        if (path.substr(0, 1) == '/' || path.length === 0) {
          names.splice(0, 1);
        }
        if (path.substr(path.length - 1, 1) == '/') {
          names.splice(names.length - 1, 1);
        }
        return names;
      },
      queryString: function(value) {
        if (value !== UNDEFINED) {
          var hash = this.hash();
          this.value(this.path() + (value ? '?' + value : '') + (hash ? '#' + hash : ''));
          return this;
        }
        var arr = _value.split('?');
        return arr.slice(1, arr.length).join('?').split('#')[0];
      },
      parameter: function(name, value, append) {
        var i, params;
        if (value !== UNDEFINED) {
          var names = this.parameterNames();
          params = [];
          value = value ? value.toString() : '';
          for (i = 0; i < names.length; i++) {
            var n = names[i],
              v = this.parameter(n);
            if (typeof v == STRING) {
              v = [v];
            }
            if (n == name) {
              v = (value === null || value === '') ? [] : 
                (append ? v.concat([value]) : [value]);
            }
            for (var j = 0; j < v.length; j++) {
              params.push(n + '=' + v[j]);
            }
          }
          if ($.inArray(name, names) == -1 && value !== null && value !== '') {
            params.push(name + '=' + value);
          }
          this.queryString(params.join('&'));
          return this;
        }
        value = this.queryString();
        if (value) {
          var r = [];
          params = value.split('&');
          for (i = 0; i < params.length; i++) {
            var p = params[i].split('=');
            if (p[0] == name) {
              r.push(p.slice(1).join('='));
            }
          }
          if (r.length !== 0) {
            return r.length != 1 ? r : r[0];
          }
        }
      },
      parameterNames: function() {
        var qs = this.queryString(),
          names = [];
        if (qs && qs.indexOf('=') != -1) {
          var params = qs.split('&');
          for (var i = 0; i < params.length; i++) {
            var name = params[i].split('=')[0];
            if ($.inArray(name, names) == -1) {
              names.push(name);
            }
          }
        }
        return names;
      },
      hash: function(value) {
        if (value !== UNDEFINED) {
          this.value(_value.split('#')[0] + (value ? '#' + value : ''));
          return this;
        }
        var arr = _value.split('#');
        return arr.slice(1, arr.length).join('#');
      }
    };
  })();
  
  $.fn.address = function(fn) {
    if (!$(this).attr('address')) {
      var f = function(e) {
        if (e.shiftKey || e.ctrlKey || e.metaKey) {
          return true;
        }
        if ($(this).is('a')) {
          var value = fn ? fn.call(this) : 
            /address:/.test($(this).attr('rel')) ? $(this).attr('rel').split('address:')[1].split(' ')[0] : 
            $.address.state() !== undefined && $.address.state() != '/' ? 
                $(this).attr('href').replace(new RegExp('^(.*' + $.address.state() + '|\\.)'), '') : 
                $(this).attr('href').replace(/^(#\!?|\.)/, '');
          $.address.value(value);
          e.preventDefault();
        }
      };
      $(this).click(f).live('click', f).live('submit', function(e) {
        if ($(this).is('form')) {
          var action = $(this).attr('action'),
            value = fn ? fn.call(this) : (action.indexOf('?') != -1 ? action.replace(/&$/, '') : action + '?') + 
              $(this).serialize();
          $.address.value(value);
          e.preventDefault();
        }
      }).attr('address', true);
    }
    return this;
  };
})(jQuery);

/*!
 * jScrollPane - v2.0.0beta11 - 2011-07-04
 * http://jscrollpane.kelvinluck.com/
 *
 * Copyright (c) 2010 Kelvin Luck
 * Dual licensed under the MIT and GPL licenses.
 */

(function($,window,undefined){

  $.fn.jScrollPane = function(settings)
  {
    // JScrollPane "class" - public methods are available through $('selector').data('jsp')
    function JScrollPane(elem, s)
    {
      var settings, jsp = this, pane, paneWidth, paneHeight, container, contentWidth, contentHeight,
        percentInViewH, percentInViewV, isScrollableV, isScrollableH, verticalDrag, dragMaxY,
        verticalDragPosition, horizontalDrag, dragMaxX, horizontalDragPosition,
        verticalBar, verticalTrack, scrollbarWidth, verticalTrackHeight, verticalDragHeight, arrowUp, arrowDown,
        horizontalBar, horizontalTrack, horizontalTrackWidth, horizontalDragWidth, arrowLeft, arrowRight,
        reinitialiseInterval, originalPadding, originalPaddingTotalWidth, previousContentWidth,
        wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false,
        originalElement = elem.clone(false, false).empty(),
        mwEvent = $.fn.mwheelIntent ? 'mwheelIntent.jsp' : 'mousewheel.jsp';

      originalPadding = elem.css('paddingTop') + ' ' +
                elem.css('paddingRight') + ' ' +
                elem.css('paddingBottom') + ' ' +
                elem.css('paddingLeft');
      originalPaddingTotalWidth = (parseInt(elem.css('paddingLeft'), 10) || 0) +
                    (parseInt(elem.css('paddingRight'), 10) || 0);

      function initialise(s)
      {

        var /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY,
            hasContainingSpaceChanged, originalScrollTop, originalScrollLeft,
            maintainAtBottom = false, maintainAtRight = false;

        settings = s;

        if (pane === undefined) {
          originalScrollTop = elem.scrollTop();
          originalScrollLeft = elem.scrollLeft();

          elem.css(
            {
              overflow: 'hidden',
              padding: 0
            }
          );
          // TODO: Deal with where width/ height is 0 as it probably means the element is hidden and we should
          // come back to it later and check once it is unhidden...
          paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
          paneHeight = elem.innerHeight();

          elem.width(paneWidth);
          
          pane = $('<div class="jspPane" />').css('padding', originalPadding).append(elem.children());
          container = $('<div class="jspContainer" />')
            .css({
              'width': paneWidth + 'px',
              'height': paneHeight + 'px'
            }
          ).append(pane).appendTo(elem);

          /*
          // Move any margins from the first and last children up to the container so they can still
          // collapse with neighbouring elements as they would before jScrollPane 
          firstChild = pane.find(':first-child');
          lastChild = pane.find(':last-child');
          elem.css(
            {
              'margin-top': firstChild.css('margin-top'),
              'margin-bottom': lastChild.css('margin-bottom')
            }
          );
          firstChild.css('margin-top', 0);
          lastChild.css('margin-bottom', 0);
          */
        } else {
          elem.css('width', '');

          maintainAtBottom = settings.stickToBottom && isCloseToBottom();
          maintainAtRight  = settings.stickToRight  && isCloseToRight();

          hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight;

          if (hasContainingSpaceChanged) {
            paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
            paneHeight = elem.innerHeight();
            container.css({
              width: paneWidth + 'px',
              height: paneHeight + 'px'
            });
          }

          // If nothing changed since last check...
          if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) {
            elem.width(paneWidth);
            return;
          }
          previousContentWidth = contentWidth;
          
          pane.css('width', '');
          elem.width(paneWidth);

          container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end();
        }

        pane.css('overflow', 'auto');
        if (s.contentWidth) {
          contentWidth = s.contentWidth;
        } else {
          contentWidth = pane[0].scrollWidth;
        }
        contentHeight = pane[0].scrollHeight;
        pane.css('overflow', '');

        percentInViewH = contentWidth / paneWidth;
        percentInViewV = contentHeight / paneHeight;
        isScrollableV = percentInViewV > 1;

        isScrollableH = percentInViewH > 1;

        //console.log(paneWidth, paneHeight, contentWidth, contentHeight, percentInViewH, percentInViewV, isScrollableH, isScrollableV);

        if (!(isScrollableH || isScrollableV)) {
          elem.removeClass('jspScrollable');
          pane.css({
            top: 0,
            width: container.width() - originalPaddingTotalWidth
          });
          removeMousewheel();
          removeFocusHandler();
          removeKeyboardNav();
          removeClickOnTrack();
          unhijackInternalLinks();
        } else {
          elem.addClass('jspScrollable');

          isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition);
          if (isMaintainingPositon) {
            lastContentX = contentPositionX();
            lastContentY = contentPositionY();
          }

          initialiseVerticalScroll();
          initialiseHorizontalScroll();
          resizeScrollbars();

          if (isMaintainingPositon) {
            scrollToX(maintainAtRight  ? (contentWidth  - paneWidth ) : lastContentX, false);
            scrollToY(maintainAtBottom ? (contentHeight - paneHeight) : lastContentY, false);
          }

          initFocusHandler();
          initMousewheel();
          initTouch();
          
          if (settings.enableKeyboardNavigation) {
            initKeyboardNav();
          }
          if (settings.clickOnTrack) {
            initClickOnTrack();
          }
          
          observeHash();
          if (settings.hijackInternalLinks) {
            hijackInternalLinks();
          }
        }

        if (settings.autoReinitialise && !reinitialiseInterval) {
          reinitialiseInterval = setInterval(
            function()
            {
              initialise(settings);
            },
            settings.autoReinitialiseDelay
          );
        } else if (!settings.autoReinitialise && reinitialiseInterval) {
          clearInterval(reinitialiseInterval);
        }

        originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false);
        originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false);

        elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]);
      }

      function initialiseVerticalScroll()
      {
        if (isScrollableV) {

          container.append(
            $('<div class="jspVerticalBar" />').append(
              $('<div class="jspCap jspCapTop" />'),
              $('<div class="jspTrack" />').append(
                $('<div class="jspDrag" />').append(
                  $('<div class="jspDragTop" />'),
                  $('<div class="jspDragBottom" />')
                )
              ),
              $('<div class="jspCap jspCapBottom" />')
            )
          );

          verticalBar = container.find('>.jspVerticalBar');
          verticalTrack = verticalBar.find('>.jspTrack');
          verticalDrag = verticalTrack.find('>.jspDrag');

          if (settings.showArrows) {
            arrowUp = $('<a class="jspArrow jspArrowUp" />').bind(
              'mousedown.jsp', getArrowScroll(0, -1)
            ).bind('click.jsp', nil);
            arrowDown = $('<a class="jspArrow jspArrowDown" />').bind(
              'mousedown.jsp', getArrowScroll(0, 1)
            ).bind('click.jsp', nil);
            if (settings.arrowScrollOnHover) {
              arrowUp.bind('mouseover.jsp', getArrowScroll(0, -1, arrowUp));
              arrowDown.bind('mouseover.jsp', getArrowScroll(0, 1, arrowDown));
            }

            appendArrows(verticalTrack, settings.verticalArrowPositions, arrowUp, arrowDown);
          }

          verticalTrackHeight = paneHeight;
          container.find('>.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow').each(
            function()
            {
              verticalTrackHeight -= $(this).outerHeight();
            }
          );


          verticalDrag.hover(
            function()
            {
              verticalDrag.addClass('jspHover');
            },
            function()
            {
              verticalDrag.removeClass('jspHover');
            }
          ).bind(
            'mousedown.jsp',
            function(e)
            {
              // Stop IE from allowing text selection
              $('html').bind('dragstart.jsp selectstart.jsp', nil);

              verticalDrag.addClass('jspActive');

              var startY = e.pageY - verticalDrag.position().top;

              $('html').bind(
                'mousemove.jsp',
                function(e)
                {
                  positionDragY(e.pageY - startY, false);
                }
              ).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
              return false;
            }
          );
          sizeVerticalScrollbar();
        }
      }

      function sizeVerticalScrollbar()
      {
        verticalTrack.height(verticalTrackHeight + 'px');
        verticalDragPosition = 0;
        scrollbarWidth = settings.verticalGutter + verticalTrack.outerWidth();

        // Make the pane thinner to allow for the vertical scrollbar
        pane.width(paneWidth - scrollbarWidth - originalPaddingTotalWidth);

        // Add margin to the left of the pane if scrollbars are on that side (to position
        // the scrollbar on the left or right set it's left or right property in CSS)
        try {
          if (verticalBar.position().left === 0) {
            pane.css('margin-left', scrollbarWidth + 'px');
          }
        } catch (err) {
        }
      }

      function initialiseHorizontalScroll()
      {
        if (isScrollableH) {

          container.append(
            $('<div class="jspHorizontalBar" />').append(
              $('<div class="jspCap jspCapLeft" />'),
              $('<div class="jspTrack" />').append(
                $('<div class="jspDrag" />').append(
                  $('<div class="jspDragLeft" />'),
                  $('<div class="jspDragRight" />')
                )
              ),
              $('<div class="jspCap jspCapRight" />')
            )
          );

          horizontalBar = container.find('>.jspHorizontalBar');
          horizontalTrack = horizontalBar.find('>.jspTrack');
          horizontalDrag = horizontalTrack.find('>.jspDrag');

          if (settings.showArrows) {
            arrowLeft = $('<a class="jspArrow jspArrowLeft" />').bind(
              'mousedown.jsp', getArrowScroll(-1, 0)
            ).bind('click.jsp', nil);
            arrowRight = $('<a class="jspArrow jspArrowRight" />').bind(
              'mousedown.jsp', getArrowScroll(1, 0)
            ).bind('click.jsp', nil);
            if (settings.arrowScrollOnHover) {
              arrowLeft.bind('mouseover.jsp', getArrowScroll(-1, 0, arrowLeft));
              arrowRight.bind('mouseover.jsp', getArrowScroll(1, 0, arrowRight));
            }
            appendArrows(horizontalTrack, settings.horizontalArrowPositions, arrowLeft, arrowRight);
          }

          horizontalDrag.hover(
            function()
            {
              horizontalDrag.addClass('jspHover');
            },
            function()
            {
              horizontalDrag.removeClass('jspHover');
            }
          ).bind(
            'mousedown.jsp',
            function(e)
            {
              // Stop IE from allowing text selection
              $('html').bind('dragstart.jsp selectstart.jsp', nil);

              horizontalDrag.addClass('jspActive');

              var startX = e.pageX - horizontalDrag.position().left;

              $('html').bind(
                'mousemove.jsp',
                function(e)
                {
                  positionDragX(e.pageX - startX, false);
                }
              ).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
              return false;
            }
          );
          horizontalTrackWidth = container.innerWidth();
          sizeHorizontalScrollbar();
        }
      }

      function sizeHorizontalScrollbar()
      {
        container.find('>.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow').each(
          function()
          {
            horizontalTrackWidth -= $(this).outerWidth();
          }
        );

        horizontalTrack.width(horizontalTrackWidth + 'px');
        horizontalDragPosition = 0;
      }

      function resizeScrollbars()
      {
        if (isScrollableH && isScrollableV) {
          var horizontalTrackHeight = horizontalTrack.outerHeight(),
            verticalTrackWidth = verticalTrack.outerWidth();
          verticalTrackHeight -= horizontalTrackHeight;
          $(horizontalBar).find('>.jspCap:visible,>.jspArrow').each(
            function()
            {
              horizontalTrackWidth += $(this).outerWidth();
            }
          );
          horizontalTrackWidth -= verticalTrackWidth;
          paneHeight -= verticalTrackWidth;
          paneWidth -= horizontalTrackHeight;
          horizontalTrack.parent().append(
            $('<div class="jspCorner" />').css('width', horizontalTrackHeight + 'px')
          );
          sizeVerticalScrollbar();
          sizeHorizontalScrollbar();
        }
        // reflow content
        if (isScrollableH) {
          pane.width((container.outerWidth() - originalPaddingTotalWidth) + 'px');
        }
        contentHeight = pane.outerHeight();
        percentInViewV = contentHeight / paneHeight;

        if (isScrollableH) {
          horizontalDragWidth = Math.ceil(1 / percentInViewH * horizontalTrackWidth);
          if (horizontalDragWidth > settings.horizontalDragMaxWidth) {
            horizontalDragWidth = settings.horizontalDragMaxWidth;
          } else if (horizontalDragWidth < settings.horizontalDragMinWidth) {
            horizontalDragWidth = settings.horizontalDragMinWidth;
          }
          horizontalDrag.width(horizontalDragWidth + 'px');
          dragMaxX = horizontalTrackWidth - horizontalDragWidth;
          _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons
        }
        if (isScrollableV) {
          verticalDragHeight = Math.ceil(1 / percentInViewV * verticalTrackHeight);
          if (verticalDragHeight > settings.verticalDragMaxHeight) {
            verticalDragHeight = settings.verticalDragMaxHeight;
          } else if (verticalDragHeight < settings.verticalDragMinHeight) {
            verticalDragHeight = settings.verticalDragMinHeight;
          }
          verticalDrag.height(verticalDragHeight + 'px');
          dragMaxY = verticalTrackHeight - verticalDragHeight;
          _positionDragY(verticalDragPosition); // To update the state for the arrow buttons
        }
      }

      function appendArrows(ele, p, a1, a2)
      {
        var p1 = "before", p2 = "after", aTemp;
        
        // Sniff for mac... Is there a better way to determine whether the arrows would naturally appear
        // at the top or the bottom of the bar?
        if (p == "os") {
          p = /Mac/.test(navigator.platform) ? "after" : "split";
        }
        if (p == p1) {
          p2 = p;
        } else if (p == p2) {
          p1 = p;
          aTemp = a1;
          a1 = a2;
          a2 = aTemp;
        }

        ele[p1](a1)[p2](a2);
      }

      function getArrowScroll(dirX, dirY, ele)
      {
        return function()
        {
          arrowScroll(dirX, dirY, this, ele);
          this.blur();
          return false;
        };
      }

      function arrowScroll(dirX, dirY, arrow, ele)
      {
        arrow = $(arrow).addClass('jspActive');

        var eve,
          scrollTimeout,
          isFirst = true,
          doScroll = function()
          {
            if (dirX !== 0) {
              jsp.scrollByX(dirX * settings.arrowButtonSpeed);
            }
            if (dirY !== 0) {
              jsp.scrollByY(dirY * settings.arrowButtonSpeed);
            }
            scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq);
            isFirst = false;
          };

        doScroll();

        eve = ele ? 'mouseout.jsp' : 'mouseup.jsp';
        ele = ele || $('html');
        ele.bind(
          eve,
          function()
          {
            arrow.removeClass('jspActive');
            scrollTimeout && clearTimeout(scrollTimeout);
            scrollTimeout = null;
            ele.unbind(eve);
          }
        );
      }

      function initClickOnTrack()
      {
        removeClickOnTrack();
        if (isScrollableV) {
          verticalTrack.bind(
            'mousedown.jsp',
            function(e)
            {
              if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
                var clickedTrack = $(this),
                  offset = clickedTrack.offset(),
                  direction = e.pageY - offset.top - verticalDragPosition,
                  scrollTimeout,
                  isFirst = true,
                  doScroll = function()
                  {
                    var offset = clickedTrack.offset(),
                      pos = e.pageY - offset.top - verticalDragHeight / 2,
                      contentDragY = paneHeight * settings.scrollPagePercent,
                      dragY = dragMaxY * contentDragY / (contentHeight - paneHeight);
                    if (direction < 0) {
                      if (verticalDragPosition - dragY > pos) {
                        jsp.scrollByY(-contentDragY);
                      } else {
                        positionDragY(pos);
                      }
                    } else if (direction > 0) {
                      if (verticalDragPosition + dragY < pos) {
                        jsp.scrollByY(contentDragY);
                      } else {
                        positionDragY(pos);
                      }
                    } else {
                      cancelClick();
                      return;
                    }
                    scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
                    isFirst = false;
                  },
                  cancelClick = function()
                  {
                    scrollTimeout && clearTimeout(scrollTimeout);
                    scrollTimeout = null;
                    $(document).unbind('mouseup.jsp', cancelClick);
                  };
                doScroll();
                $(document).bind('mouseup.jsp', cancelClick);
                return false;
              }
            }
          );
        }
        
        if (isScrollableH) {
          horizontalTrack.bind(
            'mousedown.jsp',
            function(e)
            {
              if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) {
                var clickedTrack = $(this),
                  offset = clickedTrack.offset(),
                  direction = e.pageX - offset.left - horizontalDragPosition,
                  scrollTimeout,
                  isFirst = true,
                  doScroll = function()
                  {
                    var offset = clickedTrack.offset(),
                      pos = e.pageX - offset.left - horizontalDragWidth / 2,
                      contentDragX = paneWidth * settings.scrollPagePercent,
                      dragX = dragMaxX * contentDragX / (contentWidth - paneWidth);
                    if (direction < 0) {
                      if (horizontalDragPosition - dragX > pos) {
                        jsp.scrollByX(-contentDragX);
                      } else {
                        positionDragX(pos);
                      }
                    } else if (direction > 0) {
                      if (horizontalDragPosition + dragX < pos) {
                        jsp.scrollByX(contentDragX);
                      } else {
                        positionDragX(pos);
                      }
                    } else {
                      cancelClick();
                      return;
                    }
                    scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq);
                    isFirst = false;
                  },
                  cancelClick = function()
                  {
                    scrollTimeout && clearTimeout(scrollTimeout);
                    scrollTimeout = null;
                    $(document).unbind('mouseup.jsp', cancelClick);
                  };
                doScroll();
                $(document).bind('mouseup.jsp', cancelClick);
                return false;
              }
            }
          );
        }
      }

      function removeClickOnTrack()
      {
        if (horizontalTrack) {
          horizontalTrack.unbind('mousedown.jsp');
        }
        if (verticalTrack) {
          verticalTrack.unbind('mousedown.jsp');
        }
      }

      function cancelDrag()
      {
        $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp');

        if (verticalDrag) {
          verticalDrag.removeClass('jspActive');
        }
        if (horizontalDrag) {
          horizontalDrag.removeClass('jspActive');
        }
      }

      function positionDragY(destY, animate)
      {
        if (!isScrollableV) {
          return;
        }
        if (destY < 0) {
          destY = 0;
        } else if (destY > dragMaxY) {
          destY = dragMaxY;
        }

        // can't just check if(animate) because false is a valid value that could be passed in...
        if (animate === undefined) {
          animate = settings.animateScroll;
        }
        if (animate) {
          jsp.animate(verticalDrag, 'top', destY,  _positionDragY);
        } else {
          verticalDrag.css('top', destY);
          _positionDragY(destY);
        }

      }

      function _positionDragY(destY)
      {
        if (destY === undefined) {
          destY = verticalDrag.position().top;
        }

        container.scrollTop(0);
        verticalDragPosition = destY;

        var isAtTop = verticalDragPosition === 0,
          isAtBottom = verticalDragPosition == dragMaxY,
          percentScrolled = destY/ dragMaxY,
          destTop = -percentScrolled * (contentHeight - paneHeight);

        if (wasAtTop != isAtTop || wasAtBottom != isAtBottom) {
          wasAtTop = isAtTop;
          wasAtBottom = isAtBottom;
          elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
        }
        
        updateVerticalArrows(isAtTop, isAtBottom);
        pane.css('top', destTop);
        elem.trigger('jsp-scroll-y', [-destTop, isAtTop, isAtBottom]).trigger('scroll');
      }

      function positionDragX(destX, animate)
      {
        if (!isScrollableH) {
          return;
        }
        if (destX < 0) {
          destX = 0;
        } else if (destX > dragMaxX) {
          destX = dragMaxX;
        }

        if (animate === undefined) {
          animate = settings.animateScroll;
        }
        if (animate) {
          jsp.animate(horizontalDrag, 'left', destX,  _positionDragX);
        } else {
          horizontalDrag.css('left', destX);
          _positionDragX(destX);
        }
      }

      function _positionDragX(destX)
      {
        if (destX === undefined) {
          destX = horizontalDrag.position().left;
        }

        container.scrollTop(0);
        horizontalDragPosition = destX;

        var isAtLeft = horizontalDragPosition === 0,
          isAtRight = horizontalDragPosition == dragMaxX,
          percentScrolled = destX / dragMaxX,
          destLeft = -percentScrolled * (contentWidth - paneWidth);

        if (wasAtLeft != isAtLeft || wasAtRight != isAtRight) {
          wasAtLeft = isAtLeft;
          wasAtRight = isAtRight;
          elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
        }
        
        updateHorizontalArrows(isAtLeft, isAtRight);
        pane.css('left', destLeft);
        elem.trigger('jsp-scroll-x', [-destLeft, isAtLeft, isAtRight]).trigger('scroll');
      }

      function updateVerticalArrows(isAtTop, isAtBottom)
      {
        if (settings.showArrows) {
          arrowUp[isAtTop ? 'addClass' : 'removeClass']('jspDisabled');
          arrowDown[isAtBottom ? 'addClass' : 'removeClass']('jspDisabled');
        }
      }

      function updateHorizontalArrows(isAtLeft, isAtRight)
      {
        if (settings.showArrows) {
          arrowLeft[isAtLeft ? 'addClass' : 'removeClass']('jspDisabled');
          arrowRight[isAtRight ? 'addClass' : 'removeClass']('jspDisabled');
        }
      }

      function scrollToY(destY, animate)
      {
        var percentScrolled = destY / (contentHeight - paneHeight);
        positionDragY(percentScrolled * dragMaxY, animate);
      }

      function scrollToX(destX, animate)
      {
        var percentScrolled = destX / (contentWidth - paneWidth);
        positionDragX(percentScrolled * dragMaxX, animate);
      }

      function scrollToElement(ele, stickToTop, animate)
      {
        var e, eleHeight, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, viewportLeft, maxVisibleEleTop, maxVisibleEleLeft, destY, destX;

        // Legal hash values aren't necessarily legal jQuery selectors so we need to catch any
        // errors from the lookup...
        try {
          e = $(ele);
        } catch (err) {
          return;
        }
        eleHeight = e.outerHeight();
        eleWidth= e.outerWidth();

        container.scrollTop(0);
        container.scrollLeft(0);
        
        // loop through parents adding the offset top of any elements that are relatively positioned between
        // the focused element and the jspPane so we can get the true distance from the top
        // of the focused element to the top of the scrollpane...
        while (!e.is('.jspPane')) {
          eleTop += e.position().top;
          eleLeft += e.position().left;
          e = e.offsetParent();
          if (/^body|html$/i.test(e[0].nodeName)) {
            // we ended up too high in the document structure. Quit!
            return;
          }
        }

        viewportTop = contentPositionY();
        maxVisibleEleTop = viewportTop + paneHeight;
        if (eleTop < viewportTop || stickToTop) { // element is above viewport
          destY = eleTop - settings.verticalGutter;
        } else if (eleTop + eleHeight > maxVisibleEleTop) { // element is below viewport
          destY = eleTop - paneHeight + eleHeight + settings.verticalGutter;
        }
        if (destY) {
          scrollToY(destY, animate);
        }
        
        viewportLeft = contentPositionX();
              maxVisibleEleLeft = viewportLeft + paneWidth;
              if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport
                  destX = eleLeft - settings.horizontalGutter;
              } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport
                  destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter;
              }
              if (destX) {
                  scrollToX(destX, animate);
              }

      }

      function contentPositionX()
      {
        return -pane.position().left;
      }

      function contentPositionY()
      {
        return -pane.position().top;
      }

      function isCloseToBottom()
      {
        var scrollableHeight = contentHeight - paneHeight;
        return (scrollableHeight > 20) && (scrollableHeight - contentPositionY() < 10);
      }

      function isCloseToRight()
      {
        var scrollableWidth = contentWidth - paneWidth;
        return (scrollableWidth > 20) && (scrollableWidth - contentPositionX() < 10);
      }

      function initMousewheel()
      {
        container.unbind(mwEvent).bind(
          mwEvent,
          function (event, delta, deltaX, deltaY) {
            var dX = horizontalDragPosition, dY = verticalDragPosition;
            jsp.scrollBy(deltaX * settings.mouseWheelSpeed, -deltaY * settings.mouseWheelSpeed, false);
            // return true if there was no movement so rest of screen can scroll
            return dX == horizontalDragPosition && dY == verticalDragPosition;
          }
        );
      }

      function removeMousewheel()
      {
        container.unbind(mwEvent);
      }

      function nil()
      {
        return false;
      }

      function initFocusHandler()
      {
        pane.find(':input,a').unbind('focus.jsp').bind(
          'focus.jsp',
          function(e)
          {
            scrollToElement(e.target, false);
          }
        );
      }

      function removeFocusHandler()
      {
        pane.find(':input,a').unbind('focus.jsp');
      }
      
      function initKeyboardNav()
      {
        var keyDown, elementHasScrolled, validParents = [];
        isScrollableH && validParents.push(horizontalBar[0]);
        isScrollableV && validParents.push(verticalBar[0]);
        
        // IE also focuses elements that don't have tabindex set.
        pane.focus(
          function()
          {
            elem.focus();
          }
        );
        
        elem.attr('tabindex', 0)
          .unbind('keydown.jsp keypress.jsp')
          .bind(
            'keydown.jsp',
            function(e)
            {
              if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)){
                return;
              }
              var dX = horizontalDragPosition, dY = verticalDragPosition;
              switch(e.keyCode) {
                case 40: // down
                case 38: // up
                case 34: // page down
                case 32: // space
                case 33: // page up
                case 39: // right
                case 37: // left
                  keyDown = e.keyCode;
                  keyDownHandler();
                  break;
                case 35: // end
                  scrollToY(contentHeight - paneHeight);
                  keyDown = null;
                  break;
                case 36: // home
                  scrollToY(0);
                  keyDown = null;
                  break;
              }

              elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition;
              return !elementHasScrolled;
            }
          ).bind(
            'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls...
            function(e)
            {
              if (e.keyCode == keyDown) {
                keyDownHandler();
              }
              return !elementHasScrolled;
            }
          );
        
        if (settings.hideFocus) {
          elem.css('outline', 'none');
          if ('hideFocus' in container[0]){
            elem.attr('hideFocus', true);
          }
        } else {
          elem.css('outline', '');
          if ('hideFocus' in container[0]){
            elem.attr('hideFocus', false);
          }
        }
        
        function keyDownHandler()
        {
          var dX = horizontalDragPosition, dY = verticalDragPosition;
          switch(keyDown) {
            case 40: // down
              jsp.scrollByY(settings.keyboardSpeed, false);
              break;
            case 38: // up
              jsp.scrollByY(-settings.keyboardSpeed, false);
              break;
            case 34: // page down
            case 32: // space
              jsp.scrollByY(paneHeight * settings.scrollPagePercent, false);
              break;
            case 33: // page up
              jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false);
              break;
            case 39: // right
              jsp.scrollByX(settings.keyboardSpeed, false);
              break;
            case 37: // left
              jsp.scrollByX(-settings.keyboardSpeed, false);
              break;
          }

          elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition;
          return elementHasScrolled;
        }
      }
      
      function removeKeyboardNav()
      {
        elem.attr('tabindex', '-1')
          .removeAttr('tabindex')
          .unbind('keydown.jsp keypress.jsp');
      }

      function observeHash()
      {
        if (location.hash && location.hash.length > 1) {
          var e,
            retryInt,
            hash = escape(location.hash) // hash must be escaped to prevent XSS
            ;
          try {
            e = $(hash);
          } catch (err) {
            return;
          }

          if (e.length && pane.find(hash)) {
            // nasty workaround but it appears to take a little while before the hash has done its thing
            // to the rendered page so we just wait until the container's scrollTop has been messed up.
            if (container.scrollTop() === 0) {
              retryInt = setInterval(
                function()
                {
                  if (container.scrollTop() > 0) {
                    scrollToElement(hash, true);
                    $(document).scrollTop(container.position().top);
                    clearInterval(retryInt);
                  }
                },
                50
              );
            } else {
              scrollToElement(hash, true);
              $(document).scrollTop(container.position().top);
            }
          }
        }
      }

      function unhijackInternalLinks()
      {
        $('a.jspHijack').unbind('click.jsp-hijack').removeClass('jspHijack');
      }

      function hijackInternalLinks()
      {
        unhijackInternalLinks();
        $('a[href^=#]').addClass('jspHijack').bind(
          'click.jsp-hijack',
          function()
          {
            var uriParts = this.href.split('#'), hash;
            if (uriParts.length > 1) {
              hash = uriParts[1];
              if (hash.length > 0 && pane.find('#' + hash).length > 0) {
                scrollToElement('#' + hash, true);
                // Need to return false otherwise things mess up... Would be nice to maybe also scroll
                // the window to the top of the scrollpane?
                return false;
              }
            }
          }
        );
      }
      
      // Init touch on iPad, iPhone, iPod, Android
      function initTouch()
      {
        var startX,
          startY,
          touchStartX,
          touchStartY,
          moved,
          moving = false;
  
        container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind(
          'touchstart.jsp',
          function(e)
          {
            var touch = e.originalEvent.touches[0];
            startX = contentPositionX();
            startY = contentPositionY();
            touchStartX = touch.pageX;
            touchStartY = touch.pageY;
            moved = false;
            moving = true;
          }
        ).bind(
          'touchmove.jsp',
          function(ev)
          {
            if(!moving) {
              return;
            }
            
            var touchPos = ev.originalEvent.touches[0],
              dX = horizontalDragPosition, dY = verticalDragPosition;
            
            jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY);
            
            moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5;
            
            // return true if there was no movement so rest of screen can scroll
            return dX == horizontalDragPosition && dY == verticalDragPosition;
          }
        ).bind(
          'touchend.jsp',
          function(e)
          {
            moving = false;
            /*if(moved) {
              return false;
            }*/
          }
        ).bind(
          'click.jsp-touchclick',
          function(e)
          {
            if(moved) {
              moved = false;
              return false;
            }
          }
        );
      }
      
      function destroy(){
        var currentY = contentPositionY(),
          currentX = contentPositionX();
        elem.removeClass('jspScrollable').unbind('.jsp');
        elem.replaceWith(originalElement.append(pane.children()));
        originalElement.scrollTop(currentY);
        originalElement.scrollLeft(currentX);
      }

      // Public API
      $.extend(
        jsp,
        {
          // Reinitialises the scroll pane (if it's internal dimensions have changed since the last time it
          // was initialised). The settings object which is passed in will override any settings from the
          // previous time it was initialised - if you don't pass any settings then the ones from the previous
          // initialisation will be used.
          reinitialise: function(s)
          {
            s = $.extend({}, settings, s);
            initialise(s);
          },
          // Scrolls the specified element (a jQuery object, DOM node or jQuery selector string) into view so
          // that it can be seen within the viewport. If stickToTop is true then the element will appear at
          // the top of the viewport, if it is false then the viewport will scroll as little as possible to
          // show the element. You can also specify if you want animation to occur. If you don't provide this
          // argument then the animateScroll value from the settings object is used instead.
          scrollToElement: function(ele, stickToTop, animate)
          {
            scrollToElement(ele, stickToTop, animate);
          },
          // Scrolls the pane so that the specified co-ordinates within the content are at the top left
          // of the viewport. animate is optional and if not passed then the value of animateScroll from
          // the settings object this jScrollPane was initialised with is used.
          scrollTo: function(destX, destY, animate)
          {
            scrollToX(destX, animate);
            scrollToY(destY, animate);
          },
          // Scrolls the pane so that the specified co-ordinate within the content is at the left of the
          // viewport. animate is optional and if not passed then the value of animateScroll from the settings
          // object this jScrollPane was initialised with is used.
          scrollToX: function(destX, animate)
          {
            scrollToX(destX, animate);
          },
          // Scrolls the pane so that the specified co-ordinate within the content is at the top of the
          // viewport. animate is optional and if not passed then the value of animateScroll from the settings
          // object this jScrollPane was initialised with is used.
          scrollToY: function(destY, animate)
          {
            scrollToY(destY, animate);
          },
          // Scrolls the pane to the specified percentage of its maximum horizontal scroll position. animate
          // is optional and if not passed then the value of animateScroll from the settings object this
          // jScrollPane was initialised with is used.
          scrollToPercentX: function(destPercentX, animate)
          {
            scrollToX(destPercentX * (contentWidth - paneWidth), animate);
          },
          // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate
          // is optional and if not passed then the value of animateScroll from the settings object this
          // jScrollPane was initialised with is used.
          scrollToPercentY: function(destPercentY, animate)
          {
            scrollToY(destPercentY * (contentHeight - paneHeight), animate);
          },
          // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
          // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
          scrollBy: function(deltaX, deltaY, animate)
          {
            jsp.scrollByX(deltaX, animate);
            jsp.scrollByY(deltaY, animate);
          },
          // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
          // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
          scrollByX: function(deltaX, animate)
          {
            var destX = contentPositionX() + Math[deltaX<0 ? 'floor' : 'ceil'](deltaX),
              percentScrolled = destX / (contentWidth - paneWidth);
            positionDragX(percentScrolled * dragMaxX, animate);
          },
          // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
          // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
          scrollByY: function(deltaY, animate)
          {
            var destY = contentPositionY() + Math[deltaY<0 ? 'floor' : 'ceil'](deltaY),
              percentScrolled = destY / (contentHeight - paneHeight);
            positionDragY(percentScrolled * dragMaxY, animate);
          },
          // Positions the horizontal drag at the specified x position (and updates the viewport to reflect
          // this). animate is optional and if not passed then the value of animateScroll from the settings
          // object this jScrollPane was initialised with is used.
          positionDragX: function(x, animate)
          {
            positionDragX(x, animate);
          },
          // Positions the vertical drag at the specified y position (and updates the viewport to reflect
          // this). animate is optional and if not passed then the value of animateScroll from the settings
          // object this jScrollPane was initialised with is used.
          positionDragY: function(y, animate)
          {
            positionDragY(y, animate);
          },
          // This method is called when jScrollPane is trying to animate to a new position. You can override
          // it if you want to provide advanced animation functionality. It is passed the following arguments:
          //  * ele          - the element whose position is being animated
          //  * prop         - the property that is being animated
          //  * value        - the value it's being animated to
          //  * stepCallback - a function that you must execute each time you update the value of the property
          // You can use the default implementation (below) as a starting point for your own implementation.
          animate: function(ele, prop, value, stepCallback)
          {
            var params = {};
            params[prop] = value;
            ele.animate(
              params,
              {
                'duration'  : settings.animateDuration,
                'easing'  : settings.animateEase,
                'queue'    : false,
                'step'    : stepCallback
              }
            );
          },
          // Returns the current x position of the viewport with regards to the content pane.
          getContentPositionX: function()
          {
            return contentPositionX();
          },
          // Returns the current y position of the viewport with regards to the content pane.
          getContentPositionY: function()
          {
            return contentPositionY();
          },
          // Returns the width of the content within the scroll pane.
          getContentWidth: function()
          {
            return contentWidth;
          },
          // Returns the height of the content within the scroll pane.
          getContentHeight: function()
          {
            return contentHeight;
          },
          // Returns the horizontal position of the viewport within the pane content.
          getPercentScrolledX: function()
          {
            return contentPositionX() / (contentWidth - paneWidth);
          },
          // Returns the vertical position of the viewport within the pane content.
          getPercentScrolledY: function()
          {
            return contentPositionY() / (contentHeight - paneHeight);
          },
          // Returns whether or not this scrollpane has a horizontal scrollbar.
          getIsScrollableH: function()
          {
            return isScrollableH;
          },
          // Returns whether or not this scrollpane has a vertical scrollbar.
          getIsScrollableV: function()
          {
            return isScrollableV;
          },
          // Gets a reference to the content pane. It is important that you use this method if you want to
          // edit the content of your jScrollPane as if you access the element directly then you may have some
          // problems (as your original element has had additional elements for the scrollbars etc added into
          // it).
          getContentPane: function()
          {
            return pane;
          },
          // Scrolls this jScrollPane down as far as it can currently scroll. If animate isn't passed then the
          // animateScroll value from settings is used instead.
          scrollToBottom: function(animate)
          {
            positionDragY(dragMaxY, animate);
          },
          // Hijacks the links on the page which link to content inside the scrollpane. If you have changed
          // the content of your page (e.g. via AJAX) and want to make sure any new anchor links to the
          // contents of your scroll pane will work then call this function.
          hijackInternalLinks: function()
          {
            hijackInternalLinks();
          },
          // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was
          // initialised.
          destroy: function()
          {
              destroy();
          }
        }
      );
      
      initialise(s);
    }

    // Pluginifying code...
    settings = $.extend({}, $.fn.jScrollPane.defaults, settings);
    
    // Apply default speed
    $.each(['mouseWheelSpeed', 'arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function() {
      settings[this] = settings[this] || settings.speed;
    });

    return this.each(
      function()
      {
        var elem = $(this), jspApi = elem.data('jsp');
        if (jspApi) {
          jspApi.reinitialise(settings);
        } else {
          jspApi = new JScrollPane(elem, settings);
          elem.data('jsp', jspApi);
        }
      }
    );
  };

  $.fn.jScrollPane.defaults = {
    showArrows          : false,
    maintainPosition      : true,
    stickToBottom        : false,
    stickToRight        : false,
    clickOnTrack        : true,
    autoReinitialise      : false,
    autoReinitialiseDelay    : 500,
    verticalDragMinHeight    : 0,
    verticalDragMaxHeight    : 99999,
    horizontalDragMinWidth    : 0,
    horizontalDragMaxWidth    : 99999,
    contentWidth        : undefined,
    animateScroll        : false,
    animateDuration        : 300,
    animateEase          : 'linear',
    hijackInternalLinks      : false,
    verticalGutter        : 4,
    horizontalGutter      : 4,
    mouseWheelSpeed        : 0,
    arrowButtonSpeed      : 0,
    arrowRepeatFreq        : 50,
    arrowScrollOnHover      : false,
    trackClickSpeed        : 0,
    trackClickRepeatFreq    : 70,
    verticalArrowPositions    : 'split',
    horizontalArrowPositions  : 'split',
    enableKeyboardNavigation  : true,
    hideFocus          : false,
    keyboardSpeed        : 0,
    initialDelay                : 300,        // Delay before starting repeating
    speed            : 30,    // Default speed when others falsey
    scrollPagePercent      : .8    // Percent of visible area scrolled when pageUp/Down or track area pressed
  };

})(jQuery,this);




/* DigitalGlobe Application script
*  Copyright (c)2011 DigitalGlobe
*/
var Drupal = {
  settings : {}
};

(function($) {
  $(document).ready(
      function() {
        var footer_open = false;
        $('html').removeClass('no-js');

        // Various fixups we can't do with drupal
        $('#webform-client-form-240').attr('action', '');
        $('#edit-submitted-country option[value="GS"]').text('South Georgia');
        $('a.bottom[href$="/partners"]').closest('.page-nugget').css('min-height', '180px');
        $('a.bottom[href$="/resources/coverage-video"]').closest('.page-nugget').css('min-height', '140px');

        $('.ie7 .page-nugget h2').each(function() {
          var t = $(this).text();
          if(t === 'OurEvents' || t === 'Company' || t === 'ContentCollection'
             || t === 'NewsRoom' || t === 'OurEvents' || t === 'CareerOpportunities'
             || t === 'Investors') {
            $(this).closest('.page-nugget').css('height', '250px');
          }
        });

        $('.ie7 #edit-actions input[type="submit"]').val('');

        $('#block-menu-menu-footer-menu li.last a').click(function() {
          if(footer_open) {
            $('#block-sitemap-sitemap').fadeOut('fast');
          }

          var size = (footer_open ? '-' : '+') + '=' + $('#block-sitemap-sitemap').height() + 'px';
          var was_open = footer_open;
          $('.footer-wrapper').animate({
            'marginBottom': size
          }, 'normal', 'easeOutExpo', function() {
            if(!was_open) {
              $('#block-sitemap-sitemap').fadeIn('fast');
            }
          });

          $('html, body').animate({
            'scrollTop': size
          }, 'normal', 'easeOutExpo');

          footer_open = !footer_open;

          return false;
        });

        $('div.vjs-big-play-button').live('mouseover', function(){
          $(this).addClass('vjs-big-play-button-hover');
        }).live('mouseout', function(){
          $(this).removeClass('vjs-big-play-button-hover');
          $(this).removeClass('vjs-big-play-button-active');
        });

        $('div.vjs-big-play-button').live('mousedown', function(){
          $(this).addClass('vjs-big-play-button-active');
        }).live('mouseup', function(){
          $(this).removeClass('vjs-big-play-button-active');
        });

        if(typeof window.flowplayer === 'function' && 
           ($.browser.mozilla || ($.browser.msie && $.browser.version < 9))
          && $('#flashplayer').size() > 0)
        {
          $('video').css('display', 'none');

          $('#flashplayer').css('display', 'block');
          try{
            flowplayer("flashplayer", { wmode: 'opaque', src: 'http://releases.flowplayer.org/swf/flowplayer-3.2.7.swf'}, {
                playlist: [
                  {
                    url: $('#flashplayer').data('poster'),
                    scaling: 'orig'
                  },
                  {
                    url: $('#flashplayer').attr('href'),
                    autoPlay: false,
                    autoBuffering: true
                  },
                  {
                    url: $('#flashplayer').data('poster'),
                    scaling: 'orig'
                  }
                ]
              }
            );
          }
          catch(ex){
            //No flashplayer
          }
        }

        if (typeof ($.fn.spotlight) === 'function') {
          if ($('.block-spotlight').length > 0) {

            actionVideoPlaying = function(instance) {
              instance.spotlightThumbnails.fadeOut();
              instance.navSelectedIndicator.fadeOut();
              instance.spotlightItems.find('.spot-info').stop(true, true);
              instance.spotlightItems.find('.spot-info').fadeOut();
              instance.opts.paused = true;
            }

            actionVideoPaused = function(instance, finished) {
              instance.spotlightThumbnails.fadeIn();
              instance.navSelectedIndicator.fadeIn();
              instance.spotlightItems.find('.spot-info').stop(true, true);
              instance.spotlightItems.find('.spot-info').fadeIn();
              instance.opts.paused = false;
              if(finished){
                instance.autoswitch(false);
              }
            }

            $('.block-spotlight').spotlight(
                {
                  'autoswitchsecondsMax': 8,
                  'autoswitchsecondsMin': 8,
                  'beforeswitch' : function(nextListItem, callback) {
                    nextListItem.siblings().find('.spot-info:visible').fadeOut(
                        "fast", function() {
                          if (callback)
                            callback();
                        });
                  },
                  'afterswitch' : function(nextListItem, callback) {
                    nextListItem.find('.spot-info').fadeIn();

                    if (callback)
                      callback();
                  },
                  'init': function(instance){
                    $('video').each(function(){
                      VideoJS.addListener($(this)[0], "play", function() {
                        actionVideoPlaying(instance);
                      });

                      VideoJS.addListener($(this)[0], "pause", function() {
                        actionVideoPaused(instance, false);
                      });

                      VideoJS.addListener($(this)[0], "ended", function() {
                        actionVideoPaused(instance, true);
                      });
                    });

                    if(typeof window.flowplayer === 'function' && ($.browser.mozilla || ($.browser.msie && $.browser.version < 9))) {
                      $('video').css('display', 'none');

                      $('#flashplayer').css('display', 'block');
                      try{
                        flowplayer("flashplayer", { wmode: 'opaque', src: 'http://releases.flowplayer.org/swf/flowplayer-3.2.7.swf'}, {
                          playlist: [
                            {
                              url: $('#flashplayer').data('poster'),
                              scaling: 'orig'
                            },
                            {
                              url: $('#flashplayer').attr('href'),
                              autoPlay: false,
                              autoBuffering: false,
                              // a clip event is defined inside clip object
                              onStart: function() {
                                actionVideoPlaying(instance);
                              },
                              onPause: function() {
                                actionVideoPaused(instance, false);
                              },
                              onResume: function() {
                                actionVideoPlaying(instance);
                              },
                              onFinish: function(){
                                actionVideoPaused(instance, true);
                              }
                            },
                            {
                              url: $('#flashplayer').data('poster'),
                              scaling: 'orig'
                            }
                          ]}
                        );
                      }
                      catch(ex){
                        //No Flashplayer
                      }
                    }
                  }
                });
          }

          if ($('.block-gallery').length > 0) {
            $('.block-gallery').spotlight(
                {
                  'thumbnailStyle' : 'anchored',
                  'thumbnailPageSize' : 18,
                  'autoswitchOn' : false,
                  'beforeswitch' : function(nextListItem, callback) {
                    nextListItem.siblings().find('.spot-info:visible').fadeOut(
                        "fast", function() {
                          if (callback)
                            callback();
                        });
                  },
                  'afterswitch' : function(nextListItem, callback) {
                    nextListItem.find('.spot-info').fadeIn();

                    if (callback)
                      callback();
                  }
                });
          }

          $('.spot-info').spotlightInfoCollapse();
        }

        // Enhance meganav
        $('.secnav-5').before('<th><div class="navicon navicon-globe"></div></th>');
        $('.secnav-6').before('<th><div class="navicon navicon-partners"></div></th>')
            .after('<th style="width: 200px;"></th>');
        $('.secnav-7').before('<th><div class="navicon navicon-findpartner"></div></th>');
        $('.secnav-8').before('<th><div class="navicon navicon-alliance"></div></th>');
        $('.secnav-9').before('<th><div class="navicon navicon-mfg"></div></th>');

        $('.secnav-15').before('<th><div class="navicon navicon-documents"></div></th>');
        $('.secnav-16').before('<th><div class="navicon navicon-earth"></div></th>')
            .after('<th style="width: 200px;"></th>');

        //Remove these options until the pages are ready
        //$('.secnav-10').before('<th><div class="navicon navicon-software"></div></th>');
        //$('.secnav-18').before('<th><div class="navicon navicon-samples"></div></th>');

        /* MegaNav Nav/Page Nav submenu display */
        (function(settings) {
          var opts = {
            hideSubMenuEvent: null,
            showSubMenuEvent: null
          };

          //merge defaults with custom defined options
          if (settings) {
            $.extend(opts, settings);
          }

          var hovering = false;

          var hideSubMenu = function(sec, speed) {
            if (typeof speed === 'undefined')
              speed = 'fast';

            sec.fadeOut(speed);

            if(opts.hideSubMenuEvent != null) {
              $(document).trigger(opts.hideSubMenuEvent);
            }
          };

          var queueClose = function(sec) {
            if(sec.is(':visible')) {
              sec.data('tid', window.setTimeout(function() {
                if (!hovering)
                  hideSubMenu(sec, 0);
              }, 200));
            }
          };

          var cancelClose = function(sec) {
            window.clearTimeout(sec.data('tid'));
          };

          $('.secondary:not(:animated)').mouseenter(function() {
            hovering = true;
            cancelClose($(this));
          }).mouseleave(function() {
            hovering = false;
            queueClose($(this));
          });

          $('#primary a.top, nav.content a.top').hoverIntent({
            over : function() {
              var sec = $(this).closest('li').find('.secondary');

              if (sec.size() > 0) {
                hideSubMenu(sec, 0);
                cancelClose(sec);
              }

              sec.show(0);

              if(opts.showSubMenuEvent != null){
                $(document).trigger(opts.showSubMenuEvent);
              }
            },
            timeout : 200,
            out : function() {
              var sec = $(this).closest('li').find('.secondary');
              queueClose(sec);
            }
          });
        })({'showSubMenuEvent': 'pause_spotlight', 'hideSubMenuEvent': 'resume_spotlight'});

        /* Related Docs submenu display */
        (function() {
          var hovering = false;

          var hideSubMenu = function(sec) {
            sec.animate({
              'top' : '0px'
            }, "fast", function() {
              $(this).hide(0);
            });
          };

          var queueClose = function(sec) {
            sec.data('tid', window.setTimeout(function() {
              if (!hovering) {
                hideSubMenu(sec);
              }
            }, 200));
          };

          var cancelClose = function(sec) {
            window.clearTimeout(sec.data('tid'));
          };

          var rel_docs = {
            over : function() {
              var sec = $(this).closest('li').find('.menu-sec-wrapper');

              if (!sec.is(':visible')) {
                sec.addClass('selected');

                if (sec.size() > 0) {
                  hideSubMenu($('.related-docs .menu-sec-wrapper').not(sec));
                  cancelClose(sec);
                }

                sec.show(0, function() {
                  var height = Math.min(250, $(this).find('.jspPane').height());
                  $(this).height(height);
                  $(this).animate({
                    'top' : "-=" + height
                  });
                });
              }
            },
            timeout : 200,
            out : function() {
              var sec = $(this).closest('li').find('.menu-sec-wrapper');
              sec.removeClass('selected');
              queueClose(sec);
            }
          };

          $('#container').change(function(){
            $('.related-docs li').hoverIntent(rel_docs);
          });

          $('.related-docs li').hoverIntent(rel_docs);

          var sb = $('.related-docs .scrollbar');
          if(typeof $.fn.jScrollPane === 'function' && sb.children('.jspContainer').size() == 0
              && sb.closest('.vertical-tab-wrapper').length > 0) {
            sb.jScrollPane();
            sb.css('display', 'none');
          }
        })();

        $('.product-samples .download').live('click', function(){
          $path = $(this).siblings('select').val();
          if($path != ''){
            document.location = $path;
          }
        });


        /** ******** Expandable Product Detail View ********** */
        (function(settings) {
          var defaultopts = {
            containerSelector : ".expandable"
          };

          // merge defaults with custom defined options
          if (settings) {
            $.extend(defaultopts, settings);
          }

          var init = function() {
            $(defaultopts.containerSelector).find(".desc").each(function() {
              $(this).hide();
            });
          };

          var toggleOpen = function($title, $desc, quick){
            $title.toggleClass('open');

            methodShow = (quick ? 'show' : 'slideDown');
            methodHide = (quick ? 'hide' : 'slideUp');

            if (!$desc.is(':visible')) {
              $desc[methodShow]();
            } else {
              $desc[methodHide]();
            }
          };

          init();

          $(defaultopts.containerSelector).find(".title").live('click',
            function() {
              var $slider = $('.slider-container');

              var $next = $(this).next();

              toggleOpen($(this), $next, false);
            }
          );
        })({});

        /** ******** Vertical Tabs ********** */
        (function(settings) {

          var defaultopts = {
            containerSelector : "#vertical-tabs",
            selectedClass : "selected"
          };

          // merge defaults with custom defined options
           if (settings) {
            $.extend(defaultopts, settings);
          }

          $(defaultopts.containerSelector).find('.display').removeClass(
              'display');
          $(defaultopts.containerSelector).find('.body-wrapper').eq(0)
              .addClass('display');
          $(defaultopts.containerSelector).find('.content:eq(0) h3').addClass(
              'selected');

          var selectedChange = function($title, $body, now) {
            var speed = (typeof(now) === undefined ? 'fast' : (now ? '0' : 'fast'));

            var $tabContentContainer = $(defaultopts.containerSelector).find(
                '.display');

            $(defaultopts.containerSelector).find('.' + defaultopts.selectedClass)
              .removeClass(defaultopts.selectedClass);

            $tabContentContainer.fadeOut(now ? 0 : speed, function() {
              $tabContentContainer.html($body.html());
              $title.parent().addClass(defaultopts.selectedClass);
              $tabContentContainer.fadeIn(now ? 0 : speed);
            });
          };

          $links = $(defaultopts.containerSelector).find('.title:not(.' + defaultopts.selectedClass + ')');
          var initial = true;

          $.address.init(function(event) {
            $links.address();
          }).change(function(event) {

            $links.each(function(index) {
              var value = event.value.replace(/^\//, '#');

              if ($(this).attr('href') == value || value == '#' && index == 0) {
                var $el = $(this);

                $(defaultopts.containerSelector).find(".title").removeClass(
                      'theme-color');
                $el.addClass('theme-color');

                selectedChange($el, $el.parent().next(), initial ? true : false);
                return;
              }
            });
            initial = false;
          });
        })({});
      });

  /** ******** Industry Grid ********** */
  (function(settings) {

    var defaultopts = {
      containerSelector : "#industries",
      itemSelector : '.industry',
      selectedClass : "selected"
    };

    /* merge defaults with custom defined options */
    if (settings) {
      $.extend(defaultopts, settings);
    }

    var $container = $(defaultopts.containerSelector);

    //$container.find(defaultopts.itemSelector + ' .more').hide();

    /* DOM events */
    $container.find(
        defaultopts.itemSelector + ':not(.' + defaultopts.selectedClass + ")")
        .live('mouseover', function() {
          $(this).css('z-index', 10000);
          $(this).addClass('selected');
          $(this).find('.preview').show();
        });

    $container.find(defaultopts.itemSelector + '.' + defaultopts.selectedClass)
        .live('mouseout', function() {
          $(this).css('z-index', 1000);
          $(this).removeClass('selected');
          $(this).find('.preview').hide();
        });
  })({});

  var DG = {
    slugify:function(str){
      str = str.replace(/^\s+|\s+$/g, ''); // trim
      str = str.toLowerCase();

      str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
        .replace(/\s+/g, '-') // collapse whitespace and replace by -
        .replace(/-+/g, '-'); // collapse dashes

      return str;
    }
  };
})(jQuery);

