// Fx.Base-2.0.js
//(c) 2006 Valerio Proietti (http://mad4milk.net). MIT-style license.
//moo.fx.js - depends on prototype.js OR prototype.lite.js
//version 2.0

var Fx = fx = {};
Fx.Base = Class.create({
    'setOptions': function (options) {
      this.options = Object.extend({
        onBeforeStart: function(){},
        onStart: function(){},
        onComplete: function(){},
        transition: Fx.Transitions.sineInOut,
        duration: 500,
        unit: 'px',
        wait: true,
        fps: 50
      }, options || {});
    },
    'step': function(){
      var time = new Date().getTime();
      if (time < this.time + this.options.duration) {
        this.cTime = time - this.time;
        this.setNow();
      }
      else {
        setTimeout(this.options.onComplete.bind(this, this.element), 10);
        this.clearTimer();
        this.now = this.to;
      }
      this.increase();
    },
    'setNow': function () {
      this.now = this.compute(this.from, this.to);
    },
    'compute': function (from, to) {
      var change = to - from;
      return this.options.transition(this.cTime, from, change, this.options.duration);
    },
    'clearTimer': function () {
      clearInterval(this.timer);
      this.timer = null;
      return this;
    },
    '_start': function (from, to) {
      if (!this.options.wait) this.clearTimer();
      if (this.timer) return;
      this.options.onBeforeStart();
      setTimeout(this.options.onStart.bind(this, this.element), 10);
      this.from = from;
      this.to = to;
      this.time = new Date().getTime();
      this.timer = setInterval(this.step.bind(this), Math.round(1000/this.options.fps));
      return this;
    },
    'custom': function(from, to){
      return this._start(from, to);
    },
    'set': function(to){
      this.now = to;
      this.increase();
      return this;
    },
    'hide': function(){
      return this.set(0);
    },
    'setStyle': function(e, p, v){
      if (p == 'opacity'){
        if (v == 0 && e.style.visibility != "hidden") e.style.visibility = "hidden";
        else if (e.style.visibility != "visible") e.style.visibility = "visible";
        if (window.ActiveXObject) e.style.filter = "alpha(opacity=" + v*100 + ")";
        e.style.opacity = v;
      }
      else {
        e.style[p] = v + this.options.unit;
      }
    },
    'initialize': function () {}
  }
);
Fx.Style = Class.create(Fx.Base, {
    'initialize': function (el, property, options) {
      this.element = $(el);
      this.setOptions(options);
      this.property = property.camelize();
    },
    'increase': function(){
      this.setStyle(this.element, this.property, this.now);
    }
  }
);
Fx.Styles = Class.create(Fx.Base, {
    'initialize': function (el, options) {
      this.element = $(el);
      this.setOptions(options);
      this.now = {};
    },
    'setNow': function() {
      for (p in this.from) this.now[p] = this.compute(this.from[p], this.to[p]);
    },
    'custom': function (obj) {
      if (this.timer && this.options.wait) return;
      var from = {};
      var to = {};
      for (p in obj){
        from[p] = obj[p][0];
        to[p] = obj[p][1];
      }
      return this._start(from, to);
    },
    'increase': function(){
      for (var p in this.now) this.setStyle(this.element, p, this.now[p]);
    }
  }
);

// Fx.Transition-1.5.js
//moo.fx.transitions.js - depends on prototype.js or prototype.lite.js + moo.fx.js
//Author: Robert Penner, <http://www.robertpenner.com/easing/>, modified to be used with mootools.
//License: Easing Equations v1.5, (c) 2003 Robert Penner, all rights reserved. Open Source BSD License.

Fx.Transitions = {

  linear: function(t, b, c, d){
    return c*t/d + b;
  },

  quadIn: function(t, b, c, d){
    return c*(t/=d)*t + b;
  },

  quadOut: function(t, b, c, d){
    return -c *(t/=d)*(t-2) + b;
  },

  quadInOut: function(t, b, c, d){
    if ((t/=d/2) < 1) return c/2*t*t + b;
    return -c/2 * ((--t)*(t-2) - 1) + b;
  },

  cubicIn: function(t, b, c, d){
    return c*(t/=d)*t*t + b;
  },

  cubicOut: function(t, b, c, d){
    return c*((t=t/d-1)*t*t + 1) + b;
  },

  cubicInOut: function(t, b, c, d){
    if ((t/=d/2) < 1) return c/2*t*t*t + b;
    return c/2*((t-=2)*t*t + 2) + b;
  },

  quartIn: function(t, b, c, d){
    return c*(t/=d)*t*t*t + b;
  },

  quartOut: function(t, b, c, d){
    return -c * ((t=t/d-1)*t*t*t - 1) + b;
  },

  quartInOut: function(t, b, c, d){
    if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
    return -c/2 * ((t-=2)*t*t*t - 2) + b;
  },

  quintIn: function(t, b, c, d){
    return c*(t/=d)*t*t*t*t + b;
  },

  quintOut: function(t, b, c, d){
    return c*((t=t/d-1)*t*t*t*t + 1) + b;
  },

  quintInOut: function(t, b, c, d){
    if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
    return c/2*((t-=2)*t*t*t*t + 2) + b;
  },

  sineIn: function(t, b, c, d){
    return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
  },

  sineOut: function(t, b, c, d){
    return c * Math.sin(t/d * (Math.PI/2)) + b;
  },

  sineInOut: function(t, b, c, d){
    return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
  },

  expoIn: function(t, b, c, d){
    return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
  },

  expoOut: function(t, b, c, d){
    return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
  },

  expoInOut: function(t, b, c, d){
    if (t==0) return b;
    if (t==d) return b+c;
    if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
    return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
  },

  circIn: function(t, b, c, d){
    return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
  },

  circOut: function(t, b, c, d){
    return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
  },

  circInOut: function(t, b, c, d){
    if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
    return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
  },

  elasticIn: function(t, b, c, d, a, p){
    if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; if (!a) a = 1;
    if (a < Math.abs(c)){ a=c; var s=p/4; }
    else var s = p/(2*Math.PI) * Math.asin(c/a);
    return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
  },

  elasticOut: function(t, b, c, d, a, p){
    if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; if (!a) a = 1;
    if (a < Math.abs(c)){ a=c; var s=p/4; }
    else var s = p/(2*Math.PI) * Math.asin(c/a);
    return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
  },

  elasticInOut: function(t, b, c, d, a, p){
    if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); if (!a) a = 1;
    if (a < Math.abs(c)){ a=c; var s=p/4; }
    else var s = p/(2*Math.PI) * Math.asin(c/a);
    if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
    return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
  },

  backIn: function(t, b, c, d, s){
    if (!s) s = 1.70158;
    return c*(t/=d)*t*((s+1)*t - s) + b;
  },

  backOut: function(t, b, c, d, s){
    if (!s) s = 1.70158;
    return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
  },

  backInOut: function(t, b, c, d, s){
    if (!s) s = 1.70158;
    if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
    return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
  },

  bounceIn: function(t, b, c, d){
    return c - Fx.Transitions.bounceOut (d-t, 0, c, d) + b;
  },

  bounceOut: function(t, b, c, d){
    if ((t/=d) < (1/2.75)){
      return c*(7.5625*t*t) + b;
    } else if (t < (2/2.75)){
      return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
    } else if (t < (2.5/2.75)){
      return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
    } else {
      return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
    }
  },

  bounceInOut: function(t, b, c, d){
    if (t < d/2) return Fx.Transitions.bounceIn(t*2, 0, c, d) * .5 + b;
    return Fx.Transitions.bounceOut(t*2-d, 0, c, d) * .5 + c*.5 + b;
  }

};

// Accordion-1.0.js
//by Valerio Proietti (http://mad4milk.net). MIT-style license.
//accordion.js - depends on prototype.js or prototype.lite.js + moo.fx.js
//version 2.0

var Accordion = Class.create(Fx.Base, { /*
      
      Accordion starts with an html structure like:
      
      {{{
        <div class="accordion bar">
          click here
        </div>
        <div class="accordion section">
          ...
        </div>
        <div class="accordion bar">
          click here
        </div>
        <div class="accordion section">
          ...
        </div>
      }}}
      
      and uses code like:
      
      {{{
        bars = $$('accordion.bar');
        sections = $$('accordion.section');
        var accordion = new Accordion(bars, sections);
      }}}
      
      To create the archetypal moo.fx accordion ala
      http://moofx.mad4milk.net/
      
      Like Slider, all the Fx.Base options apply and
      you can use any Fx.Transition
      
      
    */
    'extendOptions': function (options) {
      Object.extend(this.options, Object.extend({
        start: 'open-first',
        fixedHeight: false,
        fixedWidth: false,
        alwaysHide: false,
        wait: false,
        onActive: function(){},
        onBackground: function(){},
        height: true,
        opacity: true,
        width: false
      }, options || {}));
    },
    'initialize': function (togglers, elements, options) {
      this.now = {};
      this.elements = $A(elements);
      this.togglers = $A(togglers);
      this.setOptions(options);
      this.extendOptions(options);
      this.previousClick = 0;
      this.togglers.each(
        function(tog, i){
          tog.observe('click', this.handle_toggler_click.bindAsEventListener(this, i));
        }.bind(this)
      );
      this.h = {}; this.w = {}; this.o = {};
      this.elements.each(
        function(el, i) {
          this.now[i+1] = {};
          el.observe('section:resized', this.handleResize.bindAsEventListener(this));
          el.setStyle({
              'height': '0px',
              'overflow': 'hidden'
            }
          );
        }.bind(this)
      );
      switch(this.options.start){
        case 'first-open':
          var target = this.elements[0];
          var opening_height = target.scrollHeight + 'px';
          target.setStyle({
              'height': opening_height
            }
          );
        break;
        case 'open-first':
          this.showThisHideOpen(0);
        break;
        case 'none':
          this.previousClick = -1;
        break;
      }
    },
    'setNow': function () {
      for (var i in this.from){
        var iFrom = this.from[i];
        var iTo = this.to[i];
        var iNow = this.now[i] = {};
        for (var p in iFrom) iNow[p] = this.compute(iFrom[p], iTo[p]);
      }
    },
    'custom': function (objObjs) {
      if (this.timer && this.options.wait) return;
      var from = {};
      var to = {};
      for (var i in objObjs){
        var iProps = objObjs[i];
        var iFrom = from[i] = {};
        var iTo = to[i] = {};
        for (var prop in iProps){
          iFrom[prop] = iProps[prop][0];
          iTo[prop] = iProps[prop][1];
        }
      }
      return this._start(from, to);
    },
    'hideThis': function (i) {
      if (this.options.height) this.h = {'height': [this.elements[i].offsetHeight, 0]};
      if (this.options.width) this.w = {'width': [this.elements[i].offsetWidth, 0]};
      if (this.options.opacity) this.o = {'opacity': [this.now[i+1]['opacity'] || 1, 0]};
    },
    'showThis': function (i) {
      var target = this.elements[i];
      if (this.options.height) {
        var oh = target.offsetHeight;
        var sh = target.scrollHeight;
        var kh = 0;
        this.h = {
          'height': [oh, oh]
        };
        if (this.options.fixedHeight) {
          this.h = {
            'height': [oh, this.options.fixedHeight]
          };
        }
        else {
          if (oh < sh) {
            this.h = {
              'height': [oh, sh]
            };
          }
          else {
            // see if we need to shrink it
            target.childElements().each(
              function (child) {
                kh += child.offsetHeight;
              }.bind(this)
            );
            if (kh < oh) {
              this.h = {
                'height': [oh, kh]
              };
            }
          }
        }
        /*this.h = {
          'height': [
            this.elements[i].offsetHeight, 
            this.options.fixedHeight || this.elements[i].scrollHeight
          ]
        };*/
      }
      if (this.options.width) this.w = {'width': [this.elements[i].offsetWidth, this.options.fixedWidth || this.elements[i].scrollWidth]};
      if (this.options.opacity) this.o = {'opacity': [this.now[i+1]['opacity'] || 0, 1]};
    },
    'showThisHideOpen': function (iToShow) {
      if (iToShow != this.previousClick) {
        var target_element = this.elements[iToShow];
        if (target_element) {
          this.elements[iToShow].fire('accordion:state:changed', {
              'index': iToShow
            }
          );
        }
      }
      this.previousClick = iToShow;
      var objObjs = {};
      var err = false;
      var madeInactive = false;
      this.elements.each(function(el, i){
        this.now[i] = this.now[i] || {};
        if (i != iToShow){
          this.hideThis(i);
        }
        else if (this.options.alwaysHide) {
          if (el.offsetHeight == el.scrollHeight) {
            this.hideThis(i);
            madeInactive = true;
          } 
          else /*if (el.offsetHeight == 0) */ {
            this.showThis(i);
          } 
          /*else {
            err = true;
          }*/
        }
        else if (this.options.wait && this.timer){
          this.previousClick = 'nan';
          err = true;
        } 
        else {
          this.showThis(i);
        }
        objObjs[i+1] = Object.extend(this.h, Object.extend(this.o, this.w));
      }.bind(this));
      if (err) return;
      if (!madeInactive) this.options.onActive.call(this, this.togglers[iToShow], iToShow);
      this.togglers.each(function(tog, i){
        if (i != iToShow || madeInactive) this.options.onBackground.call(this, tog, i);
      }.bind(this));
      return this.custom(objObjs);
    },
    'handle_toggler_click': function (e, iToShow) {
      this.showThisHideOpen(iToShow);
    },
    'increase': function () {
      for (var i in this.now){
        var iNow = this.now[i];
        for (var p in iNow) this.setStyle(this.elements[parseInt(i)-1], p, iNow[p]);
      }
    },
    'handleResize': function (event) {
      if (hasattr(event, 'stop')) {
        event.stop();
      }
      this.showThisHideOpen(this.previousClick);
    }
  }
);

// ExpandableResultsView.js
var ExpandableResultsView = Class.create({ /*
      
      ExpandableResultsView takes a lost of bars
      and a list of sections, ala:
      
      {{{
        
        <h2 class="bar">
          <a class="arrow" href="#">
            Close
          </a>
          Heading 1
        </h2>
        <div class="section">
          ...
          
        </div>
        
        <h2 class="bar">
          <a class="arrow" href="#">
            Close
          </a>
          Heading 1
        </h2>
        <div class="section">
          ...
          
        </div>
        ...
        ...
        
        
      }}}
      
      Clicking the arrow:
      
       * toggle()'s the section
       * add/Removes a closed class from the bar
       * toggles the arrow text from Close to Open
      
      If a bar has the class name 'closed-to-begin-with',
      then it's closed to begin with ;)
      
      {{{
        
        <h2 class="bar closed-to-begin-with">
          ...
        </h2>
        ...
        ...
        
        
      }}}
      
      
    */
    'first_run' : true,
    '_process_bar': function (bar) {
      bar.toggleClassName('closed');
      // toggle the visibility of the section
      var i = this.bars.indexOf(bar);
      var section = this.sections[i];
      
      if( section.hasClassName('slide') ){

        if( this.first_run ){
            section.setStyle({ display : 'none' });
        }else{
            $$('.troublemaker').each( function(troublemaker){
                if( troublemaker.descendantOf(section) ){
                    
                    if( section.getStyle('display') == 'none' )
                        troublemaker.show();
                    else
                        troublemaker.hide();

                }
            });
            Effect.toggle(section, 'slide', { duration : 0.3 } );
        }

      }else{
        section.toggle();
      }
        
      // toggle the text of the arrow, if present
      var arrow = bar.down('.' + this.options.classNames.arrow);
      var expanded = false;
      if (arrow) {
        if (bar.hasClassName('closed')) {
          if (this.options.should_update_arrow_text) {
            arrow.update(this.options.closed_arrow_text);
          }
          this.bars.invoke('observe', 'click', this.handle_click);
        }
        else {
          if (this.options.should_update_arrow_text) {
            arrow.update(this.options.open_arrow_text);
          }
          this.bars.invoke('stopObserving', 'click', this.handle_click);
          expanded = true;
        }
      }
      
      // toggle the descriptive part
      var descriptive = bar.down('.descriptive-openLink');

      if (descriptive) {
        if (bar.hasClassName('closed')) {
          descriptive.observe('click', this.handle_click);
        }
        else {
          descriptive.stopObserving('click', this.handle_click);
          descriptive.observe('click', this.handle_click);
        }
      }

      return expanded;
    },
    '_handle_faux_click': function (event) {
      var bar = event.findElement('.' + this.options.classNames.bar);
      var foo = this._process_bar(bar);
    },
    '_handle_click': function (event) {
      if (this.options.stop_event) {
        event.stop();
      }
      var bar = event.findElement('.' + this.options.classNames.bar);
      fire('result:expansion-state:changed', {
          'expanded': this._process_bar(bar),
          'id': bar.identify()
        }
      );
    },
    'initialize': function (container, options) {
      this.options = Object.extend({
          'classNames': {
            'bar': 'bar',
            'section': 'section',
            'arrow': 'arrow',
            'closed': 'closed'
          },
          'stop_event': true,
          'should_update_arrow_text': true,
          'open_arrow_text': 'hide',
          'closed_arrow_text': 'expand',
          'effectMode' : false
        }, options || {}
      );

      var container = $(container);
      this.bars = container.select('.' + this.options.classNames.bar);
      this.arrows = container.select('.' + this.options.classNames.arrow);
      this.sections = container.select('.' + this.options.classNames.section);
      this.handle_click = this._handle_click.bindAsEventListener(this);
      this.arrows.invoke('observe', 'click', this.handle_click);
      var handle_faux_click = this._handle_faux_click.bindAsEventListener(this);
      this.arrows.invoke('observe', 'faux:click', handle_faux_click);
      this.bars.each(
        function (bar, i) {
          if (bar.hasClassName('closed-to-begin-with')) {
            bar.removeClassName('closed-to-begin-with')
            var arrow = this.arrows[i];
            arrow.fire('faux:click');
          }
        }.bind(this)
      );
      
      this.first_run = false;
    }
  }
);

// prototip-ToolTip-1.1.0_pre1.js
//  Prototip 1.1.0_pre1
//  by Nick Stakenburg - http://www.nickstakenburg.com
//  29-10-2007
//
//  More information on this project:
//  http://www.nickstakenburg.com/projects/prototip/
//
//  Licensed under the Creative Commons Attribution 3.0 License
//  http://creativecommons.org/licenses/by/3.0/
//

var Prototip = {
  Version: '1.1.0_pre1',
  REQUIRED_Prototype: '1.6.0',
  REQUIRED_Scriptaculous: '1.7.1',
  'start': function() { this.require('Prototype'); },
  'require': function(library) {
    if ((typeof window[library] == 'undefined') ||
      (this.convertVersionString(window[library].Version) < this.convertVersionString(this['REQUIRED_' + library])))
      throw('Prototip requires ' + library + ' >= ' + this['REQUIRED_' + library]);
  },
  // based on Scriptaculous' implementation
  'convertVersionString': function(versionString) {
    var r = versionString.split('.');
    return parseInt(r[0])*100000 + parseInt(r[1])*1000 + parseInt(r[2]);
  },
  // fixed viewport.getDimensions. Also excludes scrollbars in firefox. Valid doctype required.
  'viewport': {
    'getDimensions': function() {
      var dimensions = { };
      var B = Prototype.Browser;
      $w('width height').each(function(d) {
        var D = d.capitalize();
        if (B.Opera) dimensions[d] = document.body['client' + D];
        else if (B.WebKit) dimensions[d] = self['inner' + D];
        else dimensions[d] = document.documentElement['client' + D];
        });
      return dimensions;
    }
  }
};
Prototip.start();

var Tips = {
  // Configuration
  'closeButtons': false,
  'zIndex': 1200,
  'fixIE': (function(agent){
    var version = new RegExp('MSIE ([\\d.]+)').exec(agent);
    return version ? (parseFloat(version[1]) <= 6) : false;
  })(navigator.userAgent),
  'tips': [],
  'visible': [],
  'zIndexRestore': 1200,
  'add': function(tip) {
    this.tips.push(tip);
  },
  'remove': function(element) {
    var tip = this.tips.find(function(t){ return t.element == $(element); });
    if (tip) {
      tip.deactivate();
      if (tip.tooltip) {
        tip.wrapper.remove();
        if (Tips.fixIE) tip.iframeShim.remove();
      }
      this.tips = this.tips.without(tip);
    }
  },
  'raise': function(tip) {
    var highestZ = this.zIndexHighest();
    if (!highestZ) {
      tip.style.zIndex = this.zIndexRestore;
      return;
    }
    var newZ = (tip.style.zIndex != highestZ) ? highestZ + 1 : highestZ;
    this.tips.pluck('wrapper').invoke('removeClassName', 'highest');
							
    tip.setStyle({ zIndex : newZ }).addClassName('highest');
  },
  'zIndexHighest': function() {
    var highestZ = this.visible.max(function(v) {
      return parseInt(v.style.zIndex);
    });
    return highestZ;
  },
  'addVisibile': function(tip) {
    this.removeVisible(tip);
    this.visible.push(tip);
  },
  'removeVisible': function(tip) {
    this.visible = this.visible.without(tip);
  }
};

var ToolTip = Class.create({ /*
    
    Tooltip adds a tooltip to an element.  There's a whole
    wealth of options, detailed on:
    
    http://www.nickstakenburg.com/projects/prototip
    
    But in short...
    
    {{{
      // simple usage
      new ToolTip(element, 'content');
      
      // options
      new ToolTip(
        element,                 // the id of your element
        content,                 // html
        {  
          className: 'tooltip',  // or your own class
          closeButton: false     // or true
          duration: 0.3,         // duration of the effect, if used
          delay: 0.2             // seconds before tooltip appears
          effect: false,         // false, 'appear' or 'blind'
          fixed: false,          // follow the mouse if false
          hideOn: 'mouseout'     // 'click', 'mousemove', 'mouseover',
                                    { element: 'element|target|tip|closeButton|.close',
                                      event: 'click|mouseover|mousemove' }
          hook: false,           // { element: 'topLeft|topRight|bottomLeft|bottomRight',
                                      tip: 'topLeft|topRight|bottomLeft|bottomRight' }
          offset: {x:16, y:16}   // or your own, example: {x:30, y:200}
          showOn: 'mousemove',   // or 'click', 'mouseover', 'mouseout'                              
          target: 'anotherId',   // make the tooltip appear on another element
          title: false,          // or a string, example: 'tip title'
          viewport: true         // keep within viewport, false when fixed or hooked
        }
      );
    }}}
    
    
  */
  initialize: function(element, content) {
    this.element = $(element);
    Tips.remove(this.element);
	
    this.content = content;    

    var isHooking = (arguments[2] && arguments[2].hook);
    var isShowOnClick = (arguments[2] && arguments[2].showOn == 'click');

    this.options = Object.extend({
      className: 'default',                 // see css, this will lead to .prototip .default
      closeButton: Tips.closeButtons,       // true, false
      delay: !isShowOnClick ? 0.2 : false,  // seconds before tooltip appears
      duration: 0.3,                        // duration of the effect
      effect: false,                        // false, 'appear' or 'blind'
      hideOn: 'mouseout',
      hook: false,                          // { element: topLeft|topRight|bottomLeft|bottomRight, tip: see element }
      offset: isHooking ? {x:0, y:0} : {x:16, y:16},
      fixed: isHooking ? true : false,      // follow the mouse if false
      showOn: 'mousemove',
      target: this.element,                 // or another element
      title: false,
      viewport: isHooking ? false : true    // keep within viewport if mouse is followed
    }, arguments[2] || {});

    this.target = $(this.options.target);

    this.setup();

    if (this.options.effect) {
      Prototip.require('Scriptaculous');
      this.queue = { position: 'end', limit: 1, scope: this.wrapper.identify() }
    }

    Tips.add(this);
    this.activate();
  },

  setup: function() {
    // Everything that needs to be build for observing is done here
    this.wrapper = new Element('div', { 'class' : 'prototip' }).setStyle({
      display: 'none', zIndex: Tips.zIndex++ });
    this.wrapper.identify();	

    if (Tips.fixIE) {
      this.iframeShim = new Element('iframe', { 'class' : 'iframeShim', src: 'javascript:false;' }).setStyle({
        display: 'none', zIndex: Tips.zIndexRestore - 1 });
    }

    this.tip = new Element('div', { 'class' : 'content' }).update(this.content);
    this.tip.insert(new Element('div').setStyle({ clear: 'both' }));

    if (this.options.closeButton || (this.options.hideOn.element && this.options.hideOn.element == 'closeButton'))
      this.closeButton = new Element('a', { href: 'javascript:;', 'class' : 'close' });
  },

  build: function() {
    if (Tips.fixIE) document.body.appendChild(this.iframeShim).setOpacity(0);

    // effects go smooth with extra wrapper
    var wrapper = 'wrapper';
    if (this.options.effect) {
      this.effectWrapper = this.wrapper.appendChild(new Element('div', { 'class' : 'effectWrapper' }));
      wrapper = 'effectWrapper';
    }

    this.tooltip = this[wrapper].appendChild(new Element('div', { 'class' : 'tooltip ' + this.options.className }));

    if (this.options.title || this.options.closeButton) {
      this.toolbar = this.tooltip.appendChild(new Element('div', { 'class' : 'toolbar' }));
      this.title = this.toolbar.appendChild(new Element('div', { 'class' : 'title' }).update(this.options.title || ' '));
    }

    this.tooltip.insert(this.tip);
    document.body.appendChild(this.wrapper);
	
    // fixate elements for better positioning and effects
    var fixate = (this.options.effect) ? [this.wrapper, this.effectWrapper]: [this.wrapper];
    if (Tips.fixIE) fixate.push(this.iframeShim);

    // fix width
    var fixedWidth = this.wrapper.getWidth();
    fixate.invoke('setStyle', { width: fixedWidth + 'px' });
	
    // make toolbar width fixed
    if(this.toolbar) {
      this.wrapper.setStyle({ visibility : 'hidden' }).show();
      this.toolbar.setStyle({ width: this.toolbar.getWidth() + 'px'});
      this.wrapper.hide().setStyle({ visibility : 'visible' });
    }

    // add close button
    if (this.closeButton)
      this.title.insert({ top: this.closeButton }).insert(new Element('div').setStyle({ clear: 'both' }));

    var fixedHeight = this.wrapper.getHeight();
    fixate.invoke('setStyle', { width: fixedWidth + 'px', height: fixedHeight + 'px' });

    this[this.options.effect ? wrapper : 'tooltip'].hide();
  },

  activate: function() {
    this.eventShow = this.showDelayed.bindAsEventListener(this);
    this.eventHide = this.hide.bindAsEventListener(this);

    // if fixed use mouseover instead of mousemove for less event calls
    if (this.options.fixed && this.options.showOn == 'mousemove') this.options.showOn = 'mouseover';

    if(this.options.showOn == this.options.hideOn) {
      this.eventToggle = this.toggle.bindAsEventListener(this);
      this.element.observe(this.options.showOn, this.eventToggle);
    }

    this.hideElement = Object.isUndefined(this.options.hideOn.element) ? 'element' : this.options.hideOn.element;
    var hideOptions = {
      'element': this.eventToggle ? [] : [this.element],
      'target': this.eventToggle ? [] : [this.target],
      'tip': this.eventToggle ? [] : [this.wrapper],
      'closeButton': [],
      '.close' : this.tip.select('.close')
    }
    this.hideTargets = hideOptions[this.hideElement];

    // add show and hide observers
    if (this.element && !this.eventToggle) this.element.observe(this.options.showOn, this.eventShow);
    this.hideAction = (this.options.hideOn.event || this.options.hideOn);
    if (this.hideTargets) this.hideTargets.invoke('observe', this.hideAction, this.eventHide);

    // add position observer if not fixed
    if (!this.options.fixed && this.options.showOn == 'click') {
      this.eventPosition = this.position.bindAsEventListener(this);
      this.element.observe('mousemove', this.eventPosition);
    }

    // add hide observers to close button and non click elements when they are not the close (delay needs this)
    if (this.closeButton) this.closeButton.observe('click', this.eventHide);
    if (this.options.showOn != 'click' && this.hideElement != 'element') {
      this.eventCheckDelay = this.checkDelay.bindAsEventListener(this);
      this.element.observe('mouseout', this.eventCheckDelay);
    }

    // observe wrapper to raise zIndex
    this.wrapper.observe('mouseover', function(){ Tips.raise(this.wrapper); }.bind(this));
  },

  deactivate: function() {
    if(this.options.showOn == this.options.hideOn) 
      this.element.stopObserving(this.options.showOn, this.eventToggle);
    else {
      this.element.stopObserving(this.options.showOn, this.eventShow);
      this.hideTargets.invoke('stopObserving', this.hideAction, this.eventHide);
    }

    if (this.eventPosition) this.element.stopObserving('mousemove', this.eventPosition);
    if (this.closeButton) this.closeButton.stopObserving();
    if (this.eventCheckDelay) this.element.stopObserving('mouseout', this.eventCheckDelay);
    this.wrapper.stopObserving();
  },

  showDelayed: function(event){
    if (!this.tooltip) this.build();
    this.position(event); // follow mouse
    if (this.wrapper.visible()) return;

    this.checkDelay();
    this.timer = this.show.bind(this).delay(this.options.delay);
  },

  checkDelay: function(){
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
  },

  show: function(){
    if (this.wrapper.visible() && this.options.effect != 'appear') return;

    if (Tips.fixIE) this.iframeShim.show();
    Tips.addVisibile(this.wrapper);
    this.wrapper.show();

    if (!this.options.effect) this.tooltip.show();
    else {
      if (this.activeEffect) Effect.Queues.get(this.queue.scope).remove(this.activeEffect);
      this.activeEffect = Effect[Effect.PAIRS[this.options.effect][0]](this.effectWrapper,
        { duration: this.options.duration, queue: this.queue});
    }
  },

  hide: function(){
    this.checkDelay();
    if(!this.wrapper.visible()) return;

    if (!this.options.effect) {
      if (Tips.fixIE) this.iframeShim.hide();
      this.tooltip.hide();
      this.wrapper.hide();
      Tips.removeVisible(this.wrapper);
    }
    else {
      if (this.activeEffect) Effect.Queues.get(this.queue.scope).remove(this.activeEffect);
      this.activeEffect = Effect[Effect.PAIRS[this.options.effect][1]](this.effectWrapper, 
        { duration: this.options.duration, queue: this.queue, afterFinish: function(){
        if (Tips.fixIE) this.iframeShim.hide();
        this.wrapper.hide();
        Tips.removeVisible(this.wrapper);
      }.bind(this)});
    }
  },

  toggle: function(event){
    if (this.wrapper && this.wrapper.visible()) this.hide(event);
    else this.showDelayed(event);
  },

  position: function(event){
    if (!this.wrapper.hasClassName('highest')) Tips.raise(this.wrapper);

    var offset = {left: this.options.offset.x, top: this.options.offset.y};
    var targetPosition = Position.cumulativeOffset(this.target);
    var tipd = this.wrapper.getDimensions();
    var pos = { left: (this.options.fixed) ? targetPosition[0] : Event.pointerX(event),
      top: (this.options.fixed) ? targetPosition[1] : Event.pointerY(event) };

    // add offsets
    pos.left += offset.left;
    pos.top += offset.top;

    if (this.options.hook) {
      var dims = {target: this.target.getDimensions(), tip: tipd}
      var hooks = {target: Position.cumulativeOffset(this.target), tip: Position.cumulativeOffset(this.target)}

      for(var z in hooks) {
        switch(this.options.hook[z]){
          case 'topRight':
            hooks[z][0] += dims[z].width;
            break;
          case 'bottomLeft':
            hooks[z][1] += dims[z].height;
            break;
          case 'bottomRight':
            hooks[z][0] += dims[z].width;
            hooks[z][1] += dims[z].height;
            break;
        }
      }

      // move based on hooks
      pos.left += -1*(hooks.tip[0] - hooks.target[0]);
      pos.top += -1*(hooks.tip[1] - hooks.target[1]);
    }

    // move tooltip when there is a different target
    if (!this.options.fixed && this.element !== this.target) {
      var elementPosition = Position.cumulativeOffset(this.element);
      pos.left += -1*(elementPosition[0] - targetPosition[0]);
      pos.top += -1*(elementPosition[1] - targetPosition[1]);
    }

    if (!this.options.fixed && this.options.viewport) {
      var scroll = document.viewport.getScrollOffsets();
      var viewport = Prototip.viewport.getDimensions();
      var pair = {left: 'width', top: 'height'};

      for(var z in pair) {
        if ((pos[z] + tipd[pair[z]] - scroll[z]) > viewport[pair[z]])
          pos[z] = pos[z] - tipd[pair[z]] - 2*offset[z];
      }
    }

    var finalPosition = { left: pos.left + 'px', top: pos.top + 'px' };
    this.wrapper.setStyle(finalPosition);
    if (Tips.fixIE) this.iframeShim.setStyle(finalPosition);
  }
});

// Scroller-0.1.js
var Scroller = Class.create(
  Fx.Base, {
    'increase': function() {
      this.element.scrollTop = this.now;
    },
    'up': function() {
      return this.custom(this.element.scrollTop, 0);
    },
    'down': function () {
      return this.custom(
        this.element.scrollTop, 
        this.element.scrollHeight - this.element.offsetHeight + 20
      );
    },
    'initialize': function (target, options, overflow) {
      this.element = $(target);
      this.setOptions(options);
      this.element.setStyle({
          'overflow': overflow ? overflow : 'auto'
        }
      );
      this.element.scroller = this;
    }
  }
);

// SearchInput-0.1.js
var SearchInput = Class.create({
    'extensions': {
      'default_label': '',
      'should_highlight': false,
      'getValue': function() {
        var method = this.tagName.toLowerCase();
        var value = Form.Element.Serializers[method](this);
        return (value != this.default_label ? value : '');
      },
      'present': function () {
        return this.getValue() != '';
      }
    },
    'handlers': {
      'focus': function (event) {
        if (this.value == this.default_label) {
          this.clear();
        } 
        /*
          
          if (this.should_highlight) {
            this.highlight();
          }
          
          
        */
      },
      'blur': function (event) {
        if (this.value == '') {
          this.value = this.default_label;
        }
      },
      'submit': function (event) {
        this.highlight();
      }
    },
    'initialize': function (target, default_label, should_highlight) {
      var target = $(target);
      if (default_label) {
        this.extensions.default_label = default_label;
      }
      else {
        this.extensions.default_label = target.getValue();
      }
      if (hasattr(target, 'highlight') && should_highlight) {
        this.extensions.should_highlight = true;
        target.up('form').observe('submit', this.handlers.submit.bindAsEventListener(target));
      }
      Object.extend(target, this.extensions);
      target.observe('focus', this.handlers.focus);
      target.observe('blur', this.handlers.blur);
      target.setValue(target.default_label);
    }
  }
);

// Slider-1.0.js
var Slider = Class.create(
  Fx.Base, { /*
      
      Slider takes an element with a
      container, ala:
      
      {{{
      
      <div id="example-container">
        <div id="element-to-slide">
          ...
        </div>
      </div>
      
      }}}
      
      And slides the element in and out, based on the options 
      supplied. See http://demos.mootools.net/Fx.Slide for
      the simple demo
      
      The transition can be any Fx.Transition (see Fx.Base,
      Fx.Transition & http://demos.mootools.net/Fx.Transitions
      - although note the different names in our script, which
      is the Prototype version - not the mootools version).
      
      {{{
      
      // simple usage
      var slider = new Slider(target);
      
      // set some options
      slider = new Slider(target, {
          'mode': 'horizontal',
          'transition': Fx.Transitions.backIn,
          'duration': 1000,
        }
      );
      
      // then call
      slider.toggle(); // etc. ...
        
      }}}
      
      
    */
    'initialize': function(el, options) {
      this.element = $(el);
      this.element.setStyle({'margin': 0});
      this.wrapper = this.element.up();
      this.setOptions(options);
      if (!hasattr(this.options, 'mode')) {
        this.options.mode = 'vertical';
      }
      this.now = [];
    },
    'getMode': function (mode_) {
      if (mode_) {
        return mode_;
      }
      return this.options.mode;
    },
    'setNow': function () {
      for (var i = 0; i < 2; i++) {
        this.now[i] = this.compute(this.from[i], this.to[i]);
      }
    },
    'increase': function () {
      var ms = {};
      var ls = {};
      var th = {};
      ms[this.margin] = this.now[0] + this.options.unit;
      ls[this.layout] = this.now[1] + this.options.unit;
      this.element.setStyle(ms);
      this.wrapper.setStyle(ls);
    },
    'vertical': function () {
      this.margin = 'marginTop';
      this.layout = 'height';
      this.offset = this.element.offsetHeight;
      return this.finish();
    },
    'horizontal': function () {
      this.margin = 'marginLeft';
      this.layout = 'width';
      this.offset = this.element.offsetWidth;
      return this.finish();
    },
    'finish': function () {
      return [
        parseInt(this.element.getStyle(this.margin)),
        parseInt(this.wrapper.getStyle(this.layout))
      ];
    },
    'slideIn': function (mode_) { /*
      
        Slide the elements in view horizontally or vertically,
        depending on the mode parameter or options.mode.
      
      
      */
      this.element.setStyle({'visibility': 'visible'});
      if (this.element.getStyle('display') == 'none') {
        this.hide();
        this.element.setStyle( {
            'display': 'block'
          }
        );
      }
      return this._start(this[this.getMode(mode_)](), [0, this.offset]);
    },
    'slideOut': function (mode_) { /*
      
        slide the elements out of the view horizontally or vertically,
        depending on the mode parameter or options.mode.
      
      
      */
      return this._start(this[this.getMode(mode_)](), [-this.offset, 0]);
    },
    'hide': function (mode_) { /*
      
        Hide the element without a transition.
      
      
      */
      this[this.getMode(mode_)]();
      return this.set([-this.offset, 0]);
    },
    'show': function (mode_) { /*
      
        Show the element without a transition.
      
      
      */
      this[this.getMode(mode_)]();
      return this.set([0, this.offset]);
    },
    'toggle': function (mode_) { /*
      
        Slide the element in or out,
        depending on its state.
      
      */
      if (this.wrapper.offsetHeight == 0 || this.wrapper.offsetWidth == 0) {
        return this.slideIn(mode_);
      }
      else {
        return this.slideOut(mode_);
      }
    }
  }
);

// TabView-0.9.js
var TabView = Class.create({ /*
      
      TabView takes a DOM element containing
      a markup structure typified by:
      
      {{{
        <ul class="tabs">
          <li class="tab selected">
            tab 1
          </li>
          <li class="tab">
            tab 2
          </li>
          ...
        </ul>
        <div class="panel">
          panel 1
          <ul class="sub-tabs">
            <li class="sub-tab selected">
              tab 1
            </li>
            ...
          </ul>
          <div class="sub-panel">
            sub panel 1
          </div>
        </div>
        <div class="panel">
          panle 2
        </div>
        ...
      }}}
      
      Where one tab is initially selected via
      it's class names containing 'selected'.
      
      When a tab is clicked, it:
        a. sets itself as the tab marked as selected
        b. hides all panels
        c. shows it's corresponding panel
      
      The corresponding panel is matched internally
      by index.  However, the activate method allows
      you to activate a tab/panel in all three 
      possible ways:
        a. pass activate() the index no. of the tab
           or panel.  The index no is derived from
           the order in which they appear in the
           html code.  Thus the second tab in
           the page  will open the second panel
           and so on.)
        b. pass it one of the TabView's tab or panel
           DOM elements (the TabView looks first to
           find the element in it's tabs and then
           it's panels)
        c. pass it a id string, which can:
          i. start with 'tab_'
          ii. start with 'panel_'
          iii. be stripped of it's prefix altogether
      
      Now that's a flexible widget ;)
      
      Note: option c. slightly depends on some special
      internal behaviour whereby The TabView goes and
      sets the id of each panel based on the return
      value of the $(tab).identify() method.  This
      method "returns the elementŐs id attribute if it
      exists, or sets and returns a unique, auto-
      generated id if it doesn't."
    
      This behaviour can be cancelled by passing a
      false value through as the set_panel_ids argument.
      This stops the TabView doing any auto-id setting
      but may break option c. - so turn it off at your
      own risk ;)
      
      
    */
    'tabs': [],
    'panels': [],
    'container': null,
    'showPanel': null,
    'currentPanel': null,
    '_strip_id': function ($id) {
      var ids = this.options.ids;
      var result = $id;
      if (getattr(ids, 'panel', false)) {
        result = result.sub(ids.panel, '');
      }
      if (getattr(ids, 'tab', false)) {
        result = result.sub(ids.tab, '');
      }
      return result;
    },
    '_match_id': function (target, type, id) {
      var ids = this.options.ids;
      var prefix = ids[type];
      return !!(target.identify() == prefix + id);
    },
    'initialize': function (container, options, set_panel_ids) {
      this.options = Object.extend({
          'classNames': {
            'tab': 'tab',
            'panel': 'panel',
            'tabActive': 'selected'
          },
          'ids': {
            'tab': 'tab-',
            'panel': 'panel-'
          },
          'fx': {
            'highlight': '',
            'show_panel': 'show',
            'hide_panel': 'hide'
          },
          'event_name': 'click',
          'stop_event_bubbling': true
        }, options || {}
      );
      var cls_names = this.options.classNames;
      var active = cls_names.tabActive;
      var evt = this.options.event_name;
      var panel_prefix = this.options.ids.panel;
      var container = $(container);
      this.container = container;
      this.fx = this.options.fx;
      this.panels = container.select('.' + cls_names.panel);
      this.tabs = container.select('.' + cls_names.tab);
      var default_tab, selected_tabs = this.tabs.findAll(
        function (tab, i) { /*
              
              Slightly cheekily, we apply our event listeners
              now (purely to avoid looping twice).
            
          */
          Event.observe(tab, evt, this.handle_click.bindAsEventListener(this, tab, true), false);
          if (!!(set_panel_ids)) { /*
              
              Oh yes, and apply our identification scheme at the
              same time for the same reason ;)
              
              
            */
            var id = this._strip_id(tab.identify());
            this.panels[i].setAttribute('id', panel_prefix + id);
          }
          /*
            
            Before finally getting to the point of checking
            for the selected classname...
            
            
          */
          return tab.hasClassName(active);
        }.bind(this)
      );
      /*
        
        If more than one tabs are marked as selected, we use
        the first one - as opposed to throwing an error... 
        
        If none are selected we default to the first tab on
        the page.
        
        
      */
      default_tab = selected_tabs.first();
      if (default_tab === undefined) {
        default_tab = this.tabs.first();
      }
      /*
        
        We hide all the panels and deselect all the 
        tabs before showing the selected pair
        via our main activate method.
        
        
      */
      this.tabs.invoke('removeClassName', active);
      this.panels.invoke('hide');
      this.activate(default_tab);
    },
    'handle_click': function (event, selector, triggered_by_click) {
      if (this.options.stop_event_bubbling) {
        event.stop();
      }
      this.activate(selector, triggered_by_click);
    },
    'activate': function (selector, triggered_by_click) { /*
        
        We get our selected tab via the three
        routes detailed as a. b. and c. in the
        main comment above, based on the type
        of the selector passed in.
        
      */
      var i, active = this.options.classNames.tabActive;
      switch (typeof(selector)) {
        case typeof(0):
          // we presume we've been passed an index number
          i = selector;
          break;
        case typeof(''):
          // we presume we've been passed an id string
          var target, id = this._strip_id(selector);
          target = this.tabs.find(
            function (tab) {
              return this._match_id(tab, 'tab', id);
            }.bind(this)
          );
          if (target) {
            i = this.tabs.indexOf(target);
            break;
          }
          target = this.panels.find(
            function (panel) {
              return this._match_id(panel, 'panel', id);
            }.bind(this)
          );
          i = this.panels.indexOf(target);
          break;
        default:
          // we presume we're dealing with an element
          i = this.tabs.indexOf(selector);
          if (i < 0) {
            i = this.panels.indexOf(selector);
          }
      }
      this.targetPanel = this.panels[i];
      this.targetTab = this.tabs[i];
      if (this.currentTab != this.targetTab) {
        if (triggered_by_click) {
          this.container.fire('tabview:state:changed', {
              'index': i,
              'tab': this.targetTab,
              'panel': this.targetPanel
            }
          );
        }
        if (this.currentTab) {
            /* pire */
          if( typeof(this.options.fadein) != 'undefined')
            this.currentPanel[this.fx.hide_panel]();
        else
          Effect.Fade(this.currentPanel, {duration : 0.3});

          this.currentTab.removeClassName(active);
        }
        
        this.container.fire('tabview:panel:update', {
            'index': i,
            'tab': this.targetTab,
            'panel': this.targetPanel
          }
        );
        
        if( typeof(this.options.fadein) != 'undefined')
            this.targetPanel[this.fx.show_panel]();
        else
            Effect.Appear(this.targetPanel, {delay : 0.4, duration : 0.3});

        this.targetTab.addClassName(active);
        if (this.fx.highlight) {
          this.targetTab[this.fx.highlight]();
        }
        this.currentPanel = this.targetPanel;
        this.currentTab = this.targetTab;
      }
    }
  }
);

