function Grid(columns){
  if(!(this instanceof Grid))
    return new Grid(columns);

  var pos, grid, lastEmpty, dir=1, rows, self = this;

  var row = function(r){
    if( grid[r] )
      return grid[r];
    var row = [];
    for( var x=0;x<columns;x++)
      row.push(0);
    // console.log("Created row: %j",row)
    grid.push(row);
    
    self.rows = grid.length;
    return row;
  }

  var nextEmpty = function(){
    var ey = grid.length,
      sx = dir < 0 ? columns-1 : 0,
      ex = dir > 0 ? columns   : 0;
    for(var y=lastEmpty; y<ey;y++){
      var r = row(y)
      for(var x=sx;dir>0?x<ex:x>ex;x+=dir){
        if(r[x]==0){
          pos.x = x;
          pos.y = lastEmpty = y;
          return pos;
        }
      }
    }
    return pos
  }

  var fits = function(cols,rows){
    if( dir > 0 && pos.x+cols > columns )
      return false;
    if( dir < 0 && pos.x-cols < 0 )
      return false;

    var ey = pos.y+rows,
      ex = dir > 0 ? pos.x+cols : pos.x-cols;
    for(var y=pos.y; y<ey;y++){
      var r = row(y)
      for(var x=pos.x;dir>0?x<ex:x>ex;x+=dir){
        // console.log("Fits %d,%d:",x,y,r[x])
        if(r[x]>=2){
          return false;
        }
      }
    }
    return true;
  }

  var increment = function(cols,rows,inc){
    // console.log("Incrementing %dx%d@%d,%d",cols,rows,pos.x,pos.y)
    var ey = pos.y+rows,
      ex = dir > 0 ? pos.x+cols : pos.x-cols;
    for(var y=pos.y; y<ey;y++){
      var r = row(y)
      for(var x=pos.x;dir > 0 ? x<ex : x>ex;x+=dir)
        r[x] += inc ? inc : y == pos.y || x >= ex-1 ? 1 : 2;
    }
    // For the next attempt
    pos = nextEmpty()
  }

  this.next = function(cols,rows,inc){
    if( !columns ) throw "Invalid column count.";

    if( typeof inc == "undefined" )
      inc = true;
    var y = lastEmpty;
    while(1){
      if( fits(cols,rows) ){
        inc && increment(cols,rows)
        break;
      }
      pos.x += dir;
      if( pos.x > columns ){
        pos.x  = 0;
        pos.y += 1;
      } else if( pos.x < 0 ){
        pos.x  = columns-1;
        pos.y += 1;
      }
    }
    // if( lastEmpty != y )
    //       dir = -dir;
    // console.log("Grid#next: %dx%d@%d,%d",cols,rows,pos.x,pos.y)
    return pos
  }

  this.render = function(elements,fn, c){
    // var t = "Rendering "+elements.length+" elements"
    // console.time && console.time(t)
    if(c) columns = c;
    
    this.resize(columns)
    var grid = this;
    elements.each(function(){
      var el = $(this);
      var cols = parseInt(el.data("cols")),
        rows = parseInt(el.data("rows"));
      if( !cols && el.data("cols") == "*" )
        cols = columns;
      if( !cols || !rows ) {
        console.log(el, cols, rows);
        throw "Cannot render element, must have 'cols' & 'rows' in data()";
      }
      var next = grid.next(cols,rows,false);
      var inc = fn.call(el, dir < 0 ? next.x-cols : next.x, next.y, cols, rows );
      increment(cols, rows, inc)
    })
    // console.timeEnd && console.timeEnd(t)
    return this
  }

  this.resize = function(cols){
    columns = cols || columns;
    grid = [];
    pos = dir > 0 ? {x:0,y:0} : {x:columns-1,y:0};
    lastEmpty = 0;
    return this
  }
  
  this.toString = function(){
    return $.map(grid,function(row){return row.join(",")}).join("\n");
  }
  
  this.rowsCount = function(){
    return grid.length;
  }

  if( columns )
    this.resize(columns)
};

;(function($){
  
  var slideshow
    , container
    , defaults = {};
  
  var setup = function(){
    slideshow = $(innerShiv("<section id='slideshow'><a href='#close' class=close /><div class='arrows group'></div><div class='container'></div></section>", false))
      .appendTo("body").hide();
    container = slideshow.children(".container");
    
    slideshow.click(function(e){
      if($(e.target).is("#slideshow") || $(e.target).is(".close")) {
        $.slideshow.close();
        return false;
      }
    })
  }
  
  var change = function(action){
    var curr;
    switch( action ){
      case "next":
        break;
      case "previous":
        break;
    }
    slideshow.data("current", curr);
  }
  
  $.slideshow = function(action, options){
    var prev, next;
    if( !slideshow )
      setup();
      
    if( options != null ) {
      if( options.change )
        slideshow.one("change",options.change);
      if( options.open )
        slideshow.one("open",options.open);
      if( options.close )
        slideshow.one("close",options.close);
    }
    
      switch( action ){
      case "open":
        $(".arrow", slideshow).remove();
        $("html").addClass("slideshow");
        container.children().remove();
        container.prepend( options.content );
        slideshow.show().trigger("change").trigger("open");
        
        container.addClass('loading');
        $("img", container).addClass("loading").load( function(){
          container.add(this).removeClass("loading");
          slideshow.trigger("loaded");
        })
      
        if( options.prev && options.prev.length > 0 ) {
          var prev = $("<a href=# class='arrow prev' />").appendTo($(".arrows", slideshow));
          prev.click( function(){
            options.prev.trigger("click");
          });
        }
        if( options.next && options.next.length > 0 ) {
          next = $("<a href=# class='arrow next' />").appendTo($(".arrows", slideshow));
          next.click( function(){
            options.next.trigger("click");
          });
        }
      
        $(window).unbind(".next-prev").bind("keydown.next-prev",function(e){
          switch( e.keyCode ){
            case 37: //left
              if(prev)
                prev.click();
              break;
            case 39: //right
              if(next)
                next.click();
              break;
            case 27: //esc
              $.slideshow.close();
              break;
          }
        })
      
        break;
      case "close":
        $(".arrow", slideshow).remove();
        $(window).unbind(".next-prev");
        slideshow.hide().trigger("close");
        $("html").removeClass("slideshow");
        break;
    }
  
    return slideshow;
  }
  
  // Short cuts
  $.slideshow.open = function(content,opts){
    if( $.isFunction( opts ) )
      opts = {content: content, open: opts };
    else
      opts.content = content;
      
    return $.slideshow("open",opts);
  }
  $.slideshow.close = function(opts){
    if( $.isFunction( opts ) )
      opts = {content: {}, close: opts };
    else
      opts = {content: {}};
    return $.slideshow("close", opts);
  }
  
  $.slideshow.next = function() {
    change("next");
  }
  $.slideshow.prev = function() {
    change("previous");
  }
  
})(jQuery)

;(function($){
  
  var preloader
    , defaults = {};

  
  function setup(element){
    if( element instanceof jQuery )
      preloader = element.first();
    else {
      preloader = $("<div id='preloader'><span /></div>").prependTo("body").hide();
      $(window).resize($.preloader.resize).scroll( function(){
        if( preloader.is(":visible") )
          preloader.css({
            top: $(this).scrollTop() + ($(this).height() - preloader.height()) / 2
          });
      });
    }
  }
  
  $.preloader = function(action){
    if( !preloader )
      setup(action);
    
     switch(action){
        case "show":
          preloader.fadeIn(400, "quintEaseOut");
          $(window).resize();
        break;
        case "hide":
          preloader.fadeOut(400, "quintEaseOut");
        break;
      }
      return preloader;
  }

  $.preloader.resize = function(){
    if( preloader.is(":visible") ) {
      preloader.css({
        left: ($(window).width() - preloader.width()) / 2,
        top: ($(window).scrollTop() + $(window).height() - preloader.height()) / 2
      });
    }
  }
  
  $.preloader.show = function(){
    return $.preloader("show");
  }
  
  $.preloader.hide = function(){
    return $.preloader("hide");
  }
  
})(jQuery)



/**
*  jQuery Load plugin v1.0.0
*  A hacky solution to make the load event work properly on images across browsers.
*  http://lib.publicclass.se/jquery/load
*  
*  Copyright (c) 2010 Robert Sköld
*  Dual licensed under the MIT or GPL Version 2 licenses.
*  http://jquery.org/license
*  
*  Tested on:
*   - Mozilla Firefox 3.6
*   - Safari 4.0.5
*   - Google Chrome 4.1, 5.0 & 6.0dev
*   - Microsoft Internet Explorer 7,8 & 9 (Note: in IE won't get a size until it's added to the DOM)
*   - Opera 9.64 & 10.53
*  
*  Known issues:
*   - The elements must be "img" for it to work properly. So $("div").load($.noop) 
*      will not use this hack. But $("div").children("img").load($.noop) will...
*   - IE6 doesn't work at all (never "isLoaded")
*  
*/
;(function($){
  $.fn._load = $.fn.load;
  var loadQueue = [];
  var loadCheck = function(){
    for( var i=0; i<loadQueue.length; i++ ){
      var q = loadQueue[i];
      if( isLoaded( q.img ) ) {
        q.func.call(q.img,$.Event("load"));
        loadQueue.splice( i-- , 1 );
      }
    }
    if( !loadQueue.length ) {
      clearInterval( loadInterval );
      loadInterval = undefined;
    }
  };
  
  /**
  *  Attempts to check is an img is loaded.
  *   - On IE it only needs to check for img.complete.
  *   - On Firefox it first tries to check the img width/height, unless it's set using attributes.
  *   - On Opera (and Firefox if it has width/height attributes) it uses a separate Image onload event.
  */
  var isLoaded = function(img){
    var isLoaded = img.isLoaded !== undefined ? img.isLoaded : img.complete;
    var checkLoad = $.browser.opera;
    if( checkLoad ) {
      img.isLoaded = false;
      var i = new Image();
      i.onload = function(){ img.isLoaded = true };
      i.src = img.src;
    }
    return isLoaded;
  };
  var loadInterval;
  $.fn.load = function(func){
    var imgs = this.filter("img");
    if( imgs.length > 0 && $.isFunction( func ) ){
      return imgs.each(function(){
        if( this.tagName.toLowerCase() == "img" ) {
          if( isLoaded( this ) )
            func.call(this,$.Event("load"));
          else {
            loadQueue.push( { img: this , func: func } );
            if( !loadInterval )
              loadInterval = setInterval( loadCheck , 20 );
          }
        } else {
          $(this)._load.apply($(this),arguments);
        }
      });
    } else {
      return this._load.apply(this,arguments);
    }
  };
})(jQuery)

/* innerShiv: makes HTML5shim work on innerHTML & jQuery
 * http://jdbartlett.github.com/innershiv
 *
 * This program is free software. It comes without any warranty, to
 * the extent permitted by applicable law. You can redistribute it
 * and/or modify it under the terms of the Do What The Fuck You Want
 * To Public License, Version 2, as published by Sam Hocevar. See
 * http://sam.zoy.org/wtfpl/COPYING for more details.
 */
window.innerShiv = (function () {
  var div;
  var doc = document;
  var needsShiv;
  
  // Array of elements that are new in HTML5
  var html5 = 'abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video'.split(' ');
  
  // Used to idiot-proof self-closing tags
  function fcloseTag(all, front, tag) {
    return (/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i).test(tag) ? all : front + '></' + tag + '>';
  }
  
  return function (
    html, /* string */
    returnFrag /* optional false bool */
  ) {
    if (!div) {
      div = doc.createElement('div');
      
      // needsShiv if can't use HTML5 elements with innerHTML outside the DOM
      div.innerHTML = '<nav></nav>';
      needsShiv = div.childNodes.length !== 1;
      
      if (needsShiv) {
        // MSIE allows you to create elements in the context of a document
        // fragment. Jon Neal first discovered this trick and used it in his
        // own shimprove: http://www.iecss.com/shimprove/
        var shimmedFrag = doc.createDocumentFragment();
        var i = html5.length;
        while (i--) {
          shimmedFrag.createElement(html5[i]);
        }
        
        shimmedFrag.appendChild(div);
      }
    }
    
    html = html
      // Trim whitespace to avoid unexpected text nodes in return data:
      .replace(/^\s\s*/, '').replace(/\s\s*$/, '')
      // Strip any scripts:
      .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
      // Fix misuses of self-closing tags:
      .replace(/(<([\w:]+)[^>]*?)\/>/g, fcloseTag)
      ;
    
    // Fix for using innerHTML in a table
    var tabled;
    if (tabled = html.match(/^<(tbody|tr|td|col|colgroup|thead|tfoot)/i)) {
      div.innerHTML = '<table>' + html + '</table>';
    } else {
      div.innerHTML = html;
    }
    
    // Avoid returning the tbody or tr when fixing for table use
    var scope;
    if (tabled) {
      scope = div.getElementsByTagName(tabled[1])[0].parentNode;
    } else {
      scope = div;
    }
    
    // If not in jQuery return mode, return child nodes array
    if (returnFrag === false) {
      return scope.childNodes;
    }
    
    // ...otherwise, build a fragment to return
    var returnedFrag = doc.createDocumentFragment();
    var j = scope.childNodes.length;
    while (j--) {
      returnedFrag.appendChild(scope.firstChild);
    }
    
    return returnedFrag;
  };
}());


/**
  
  jQuery plugin to expose touch restures from iPhone, iPod Touch and iPad via custom events.
  
  Based on jQuery TouchWipe extension by Andreas Waltl, netCU Internetagentur (http://www.netcu.de).
* 
* @author Kenneth Auchenberg (http://kenneth.io)
* @version 1.0

*/
;(function ($) {
  $.fn.touchEvents = function (settings) {
    var config = {
      min_move_x: 20,
      min_move_y: 20,
      preventDefaultEvents: true
    };

    if (settings) $.extend(config, settings);

    this.each(function () {
      var elmItem = $(this);
      var startX, startY, currX, currY;
      var isMoving = false;
      var isGesture = false;

      function cancelTouch(e) {
        this.removeEventListener('touchmove', onTouchMove);
        
        if (swipe) {
          var x = currX;
          var y = currY;
          var dx = startX - x;
          var dy = startY - y;
          if (Math.abs(dx) >= config.min_move_x) {
            swipe = false;
            if (dx > 0) {
              elmItem.trigger('touchSwipeLeft', e);
            }
            else {
              elmItem.trigger('touchSwipeRight', e);
            }
          }
          if (Math.abs(dy) >= config.min_move_y) {
            swipe = false;
            if (dy > 0) {
              elmItem.trigger('touchSwipeUp', e);
            }
            else {
              elmItem.trigger('touchSwipeDown', e);
            }
          }
        }
        startX = null;
        startY = null;
        isMoving = false;
        elmItem.trigger('touchEnd', [e, x, y]);
      }

      function onTouchMove(e) {
        if (e.touches.length > 1) return; // only deal with touch move

        if (config.preventDefaultEvents) {
          e.preventDefault();
        }
        
        var x = e.touches[0].pageX;
        var y = e.touches[0].pageY;
        var dx = startX - x;
        var dy = startY - y;
        elmItem.trigger('touchMove', [e, dx, dy, x, y]);
        currX = x;
        currY = y;
        
      }

      function onTouchStart(e) {
        if (e.touches.length == 1) {
          elmItem.trigger('touchStart');
          startX = e.touches[0].pageX;
          startY = e.touches[0].pageY;
          isMoving = true;
          swipe = true;
          this.addEventListener('touchmove', onTouchMove, false);
          elmItem.trigger('touchStart', [e, startX, startY]);
        }
      }

      function onGestureEnd(e) {
        isGesture = false;
        e.preventDefault();

        if (e.rotation < 5 || e.rotation > -5) {
          elmItem.trigger('touchRotated', e);
        }

        if (e.scale > 1) {
          elmItem.trigger('touchPinchOpen', e);
        }

        if (e.scale < 1) {
          elmItem.trigger('touchPinchClose', e);
        }
      }

      function onGestureStart(e) {
        isGesture = true;
      }

      function onGestureChange(e) {
        if (e.rotation < 10 || e.rotation > -10) {
          elmItem.trigger('touchRotate', e);
        }
      }

      this.addEventListener('touchstart', onTouchStart, false);
      this.addEventListener('touchend', cancelTouch, false);
      this.addEventListener('gesturestart', onGestureStart, false);
      this.addEventListener('gestureend', onGestureEnd, false);
      this.addEventListener('gesturechange', onGestureChange, false);
    });

    return this;
  };

})(jQuery)

/*
 * timeago: a jQuery plugin, version: 0.9.3 (2011-01-21)
 * @requires jQuery v1.2.3 or later
 *
 * Timeago is a jQuery plugin that makes it easy to support automatically
 * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
 *
 * For usage and examples, visit:
 * http://timeago.yarp.com/
 *
 * Licensed under the MIT:
 * http://www.opensource.org/licenses/mit-license.php
 *
 * Copyright (c) 2008-2011, Ryan McGeary (ryanonjavascript -[at]- mcgeary [*dot*] org)
 */
;(function($) {
  $.timeago = function(timestamp) {
    if (timestamp instanceof Date) {
      return inWords(timestamp);
    } else if (typeof timestamp === "string") {
      return inWords($.timeago.parse(timestamp));
    } else {
      return inWords($.timeago.datetime(timestamp));
    }
  };
  var $t = $.timeago;

  $.extend($.timeago, {
    settings: {
      refreshMillis: 60000,
      allowFuture: false,
      strings: {
        prefixAgo: null,
        prefixFromNow: null,
        suffixAgo: "ago",
        suffixFromNow: "from now",
        seconds: "less than a minute",
        minute: "about a minute",
        minutes: "%d minutes",
        hour: "about an hour",
        hours: "about %d hours",
        day: "a day",
        days: "%d days",
        month: "about a month",
        months: "%d months",
        year: "about a year",
        years: "%d years",
        numbers: []
      }
    },
    inWords: function(distanceMillis) {
      var $l = this.settings.strings;
      var prefix = $l.prefixAgo;
      var suffix = $l.suffixAgo;
      if (this.settings.allowFuture) {
        if (distanceMillis < 0) {
          prefix = $l.prefixFromNow;
          suffix = $l.suffixFromNow;
        }
        distanceMillis = Math.abs(distanceMillis);
      }

      var seconds = distanceMillis / 1000;
      var minutes = seconds / 60;
      var hours = minutes / 60;
      var days = hours / 24;
      var years = days / 365;

      function substitute(stringOrFunction, number) {
        var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
        var value = ($l.numbers && $l.numbers[number]) || number;
        return string.replace(/%d/i, value);
      }

      var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
        seconds < 90 && substitute($l.minute, 1) ||
        minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
        minutes < 90 && substitute($l.hour, 1) ||
        hours < 24 && substitute($l.hours, Math.round(hours)) ||
        hours < 48 && substitute($l.day, 1) ||
        days < 30 && substitute($l.days, Math.floor(days)) ||
        days < 60 && substitute($l.month, 1) ||
        days < 365 && substitute($l.months, Math.floor(days / 30)) ||
        years < 2 && substitute($l.year, 1) ||
        substitute($l.years, Math.floor(years));

      return $.trim([prefix, words, suffix].join(" "));
    },
    parse: function(iso8601) {
      var s = $.trim(iso8601);
      s = s.replace(/\.\d\d\d+/,""); // remove milliseconds
      s = s.replace(/-/,"/").replace(/-/,"/");
      s = s.replace(/T/," ").replace(/Z/," UTC");
      s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
      return new Date(s);
    },
    datetime: function(elem) {
      // jQuery's `is()` doesn't play well with HTML5 in IE
      var isTime = $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
      var iso8601 = isTime ? $(elem).attr("datetime") : $(elem).attr("title");
      return $t.parse(iso8601);
    }
  });

  $.fn.timeago = function() {
    var self = this;
    self.each(refresh);

    var $s = $t.settings;
    if ($s.refreshMillis > 0) {
      setInterval(function() { self.each(refresh); }, $s.refreshMillis);
    }
    return self;
  };

  function refresh() {
    var data = prepareData(this);
    if (!isNaN(data.datetime)) {
      $(this).text(inWords(data.datetime));
    }
    return this;
  }

  function prepareData(element) {
    element = $(element);
    if (!element.data("timeago")) {
      element.data("timeago", { datetime: $t.datetime(element) });
      var text = $.trim(element.text());
      if (text.length > 0) {
        element.attr("title", text);
      }
    }
    return element.data("timeago");
  }

  function inWords(date) {
    return $t.inWords(distance(date));
  }

  function distance(date) {
    return (new Date().getTime() - date.getTime());
  }

  // fix for IE6 suckage
  document.createElement("abbr");
  document.createElement("time");
}(jQuery));

/*! http://mths.be/placeholder v1.8.5 by @mathias */
;(function(window, document, $) {

  var isInputSupported = 'placeholder' in document.createElement('input'),
      isTextareaSupported = 'placeholder' in document.createElement('textarea');

  if (isInputSupported && isTextareaSupported) {

    $.fn.placeholder = function() {
      return this;
    };

    $.fn.placeholder.input = $.fn.placeholder.textarea = true;

  } else {

    $.fn.placeholder = function() {
      return this.filter((isInputSupported ? 'textarea' : ':input') + '[placeholder]')
        .bind('focus.placeholder', clearPlaceholder)
        .bind('blur.placeholder', setPlaceholder)
        .trigger('blur.placeholder').end();
    };

    $.fn.placeholder.input = isInputSupported;
    $.fn.placeholder.textarea = isTextareaSupported;

    $(function() {
      // Look for forms
      $('form').bind('submit.placeholder', function() {
        // Clear the placeholder values so they don’t get submitted
        var $inputs = $('.placeholder', this).each(clearPlaceholder);
        setTimeout(function() {
          $inputs.each(setPlaceholder);
        }, 10);
      });
    });

    // Clear placeholder values upon page reload
    $(window).bind('unload.placeholder', function() {
      $('.placeholder').val('');
    });

  }

  function args(elem) {
    // Return an object of element attributes
    var newAttrs = {},
        rinlinejQuery = /^jQuery\d+$/;
    $.each(elem.attributes, function(i, attr) {
      if (attr.specified && !rinlinejQuery.test(attr.name)) {
        newAttrs[attr.name] = attr.value;
      }
    });
    return newAttrs;
  }

  function clearPlaceholder() {
    var $input = $(this);
    if ($input.val() === $input.attr('placeholder') && $input.hasClass('placeholder')) {
      if ($input.data('placeholder-password')) {
        $input.hide().next().show().focus().attr('id', $input.removeAttr('id').data('placeholder-id'));
      } else {
        $input.val('').removeClass('placeholder');
      }
    }
  }

  function setPlaceholder() {
    var $replacement,
        $input = $(this),
        $origInput = $input,
        id = this.id;
    if ($input.val() === '') {
      if ($input.is(':password')) {
        if (!$input.data('placeholder-textinput')) {
          try {
            $replacement = $input.clone().attr({ 'type': 'text' });
          } catch(e) {
            $replacement = $('<input>').attr($.extend(args(this), { 'type': 'text' }));
          }
          $replacement
            .removeAttr('name')
            // We could just use the `.data(obj)` syntax here, but that wouldn’t work in pre-1.4.3 jQueries
            .data('placeholder-password', true)
            .data('placeholder-id', id)
            .bind('focus.placeholder', clearPlaceholder);
          $input
            .data('placeholder-textinput', $replacement)
            .data('placeholder-id', id)
            .before($replacement);
        }
        $input = $input.removeAttr('id').hide().prev().attr('id', id).show();
      }
      $input.addClass('placeholder').val($input.attr('placeholder'));
    } else {
      $input.removeClass('placeholder');
    }
  }

}(this, document, jQuery));

var bestRatio = function( w1, h1, w2, h2, fill ) {
  if( fill ) return ( ( w1 / w2 ) > ( h1 / h2 ) ) ? ( w1 / w2 ) : ( h1 / h2 );
  else return ( ( w1 / w2 ) < ( h1 / h2 ) ) ? ( w1 / w2 ) : ( h1 / h2 );
}

/* 
Robert Penner's original easing equations modified for JQuery animate method, Jamie Lemon 2009 lemonsanver.com

Below are easing equations based on Robert Penner's work, modified for JQuery
The "In" part of an animation is the start of it, the "Out" part is the end of it
If you apply "easing" at the "In" or the "Out" then the supplied animation curve is most apparent at that point
Enjoy the animation curves!

usage: $(".myImageID").animate({"left": "+=100"},{queue:false, duration:500, easing:"bounceEaseOut"});

function list:
back 
bounce
circ
cubic
elastic
expo
quad
quart
quint
sine


Note in JQuey's native animate function the supplied parameters are supplied as follows:

easingAlgorythmEaseType: function( p, n, firstNum, diff )

@param p The time phase between 0 and 1
@param n Not sure what this is :), in any case its not used
@param firstNum The first number in the transform
@param diff The difference in in pixels required

*/

/*
Disclaimer for Robert Penner's Easing Equations license:

TERMS OF USE - EASING EQUATIONS

Open source under the BSD License.

Copyright © 2001 Robert Penner
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

jQuery.extend({
    
    easing: 
    {

        // ******* back
        backEaseIn:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            var s = 1.70158; // default overshoot value, can be adjusted to suit
            return c*(p/=1)*p*((s+1)*p - s) + firstNum;
        },
        
        backEaseOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            var s = 1.70158; // default overshoot value, can be adjusted to suit
            return c*((p=p/1-1)*p*((s+1)*p + s) + 1) + firstNum;
        },
        
        backEaseInOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            var s = 1.70158; // default overshoot value, can be adjusted to suit
            if ((p/=0.5) < 1) 
                return c/2*(p*p*(((s*=(1.525))+1)*p - s)) + firstNum;
            else
                return c/2*((p-=2)*p*(((s*=(1.525))+1)*p + s) + 2) + firstNum;
        },
        
        // ******* bounce
        bounceEaseIn:function(p, n, firstNum, diff) {
            
            var c=firstNum+diff;
            var inv = this.bounceEaseOut (1-p, 1, 0, diff);
            return c - inv + firstNum;
        },
        
        bounceEaseOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;

            if (p < (1/2.75))
            {
                return c*(7.5625*p*p) + firstNum;
            }
            else if (p < (2/2.75))
            {
                return c*(7.5625*(p-=(1.5/2.75))*p + .75) + firstNum;
            }
            else if (p < (2.5/2.75))
            {
                return c*(7.5625*(p-=(2.25/2.75))*p + .9375) + firstNum;
            }
            else
            {
                return c*(7.5625*(p-=(2.625/2.75))*p + .984375) + firstNum;
            }
        },
        
        
        // ******* circ
        circEaseIn:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return -c * (Math.sqrt(1 - (p/=1)*p) - 1) + firstNum;
        },
        
        circEaseOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return c * Math.sqrt(1 - (p=p/1-1)*p) + firstNum;
        },
        
        circEaseInOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            if ((p/=0.5) < 1) 
                return -c/2 * (Math.sqrt(1 - p*p) - 1) + firstNum;
            else
                return c/2 * (Math.sqrt(1 - (p-=2)*p) + 1) + firstNum;
        },
        
        // ******* cubic
        cubicEaseIn:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return c*(p/=1)*p*p + firstNum;
        },
        
        cubicEaseOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return c*((p=p/1-1)*p*p + 1) + firstNum;
        },
        
        cubicEaseInOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            if ((p/=0.5) < 1)
                return c/2*p*p*p + firstNum;
            else
                return c/2*((p-=2)*p*p + 2) + firstNum;
        },
        
        // ******* elastic
        elasticEaseIn:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            if (p==0) return firstNum;
            if (p==1) return c;
            
            
            var peroid = 0.25;
            var s;
            var amplitude = c;
            
            if (amplitude < Math.abs(c)) 
            {
                amplitude = c;
                s = peroid/4;
            } 
            else 
            {
                s = peroid/(2*Math.PI) * Math.asin (c/amplitude);
            }
            
            return -(amplitude*Math.pow(2,10*(p-=1)) * Math.sin( (p*1-s)*(2*Math.PI)/peroid )) + firstNum;
        },
        
        elasticEaseOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            if (p==0) return firstNum;
            if (p==1) return c;
            
            var peroid = 0.25;
            var s;
            var amplitude = c;
            
            if (amplitude < Math.abs(c)) 
            {
                amplitude = c;
                s = peroid/4;
            } 
            else 
            {
                s = peroid/(2*Math.PI) * Math.asin (c/amplitude);
            }
        
            return -(amplitude*Math.pow(2,-10*p) * Math.sin( (p*1-s)*(2*Math.PI)/peroid )) + c;
        },
        
        // ******* expo
        expoEaseIn:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return (p==0) ? firstNum : c * Math.pow(2, 10 * (p - 1)) + firstNum - c * 0.001;
        },
        
        expoEaseOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return (p==1) ? c : diff * 1.001 * (-Math.pow(2, -10 * p) + 1) + firstNum;
        },
        
        expoEaseInOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            if (p==0) return firstNum;
            if (p==1) return c;
            
            if ((p/=0.5) < 1) 
                return c/2 * Math.pow(2, 10 * (p - 1)) + firstNum - c * 0.0005;
            else
                return c/2 * 1.0005 * (-Math.pow(2, -10 * --p) + 2) + firstNum;
        },
        
        // ******* quad
        quadEaseIn:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return c*(p/=1)*p + firstNum;
        },
        
        quadEaseOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return -c *(p/=1)*(p-2) + firstNum;
        },
        
        quadEaseInOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            if ((p/=0.5) < 1)
                return c/2*p*p + firstNum;
            else
                return -c/2 * ((--p)*(p-2) - 1) + firstNum;
        },

        // ******* quart
        quartEaseIn:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return c*(p/=1)*p*p*p + firstNum;
        },
        
        quartEaseOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return -c * ((p=p/1-1)*p*p*p - 1) + firstNum;
        },
        
        quartEaseInOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            if ((p/=0.5) < 1) 
                return c/2*p*p*p*p + firstNum;
            else
                return -c/2 * ((p-=2)*p*p*p - 2) + firstNum;
        },
        
        // ******* quint
        quintEaseIn:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return c*(p/=1)*p*p*p*p + firstNum;
        },
        
        quintEaseOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            return c*((p=p/1-1)*p*p*p*p + 1) + firstNum;
        },
        
        quintEaseInOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            
            if ((p/=0.5) < 1)
                return c/2*p*p*p*p*p + firstNum;
            else
                return c/2*((p-=2)*p*p*p*p + 2) + firstNum;
        },
        
        // *******  sine
        sineEaseIn:function(p, n, firstNum, diff) {
            
            var c=firstNum+diff;
            return -c * Math.cos(p * (Math.PI/2)) +c + firstNum; 
        },
        
        sineEaseOut:function(p, n, firstNum, diff) {
            
            var c=firstNum+diff;
            return c * Math.sin(p * (Math.PI/2)) + firstNum;
        },
        
        sineEaseInOut:function(p, n, firstNum, diff) {

            var c=firstNum+diff;
            return -c/2 * (Math.cos(Math.PI*p) - 1) + firstNum;
        }   
    }
});

/*
 * Modernizr v1.6.1 (with innerShiv)
 * http://www.modernizr.com
 *
 * Developed by: 
 * - Faruk Ates  http://farukat.es/
 * - Paul Irish  http://paulirish.com/
 *
 * Copyright (c) 2009-2010
 * Dual-licensed under the BSD or MIT licenses.
 * http://www.modernizr.com/license/
 */
window.Modernizr=function(l,e,q){function v(a,b){return typeof a===b}function E(a,b){for(var c in a)if(k[a[c]]!==q&&(!b||b(a[c],F)))return true}function r(a,b){var c=a.charAt(0).toUpperCase()+a.substr(1);c=(a+" "+G.join(c+" ")+c).split(" ");return!!E(c,b)}function V(){h.input=function(a){for(var b=0,c=a.length;b<c;b++)K[a[b]]=!!(a[b]in j);return K}("autocomplete autofocus list placeholder max min multiple pattern required step".split(" "));h.inputtypes=function(a){for(var b=0,c,i=a.length;b<i;b++){j.setAttribute("type",
a[b]);if(c=j.type!=="text"){j.value=L;if(/^range$/.test(j.type)&&j.style.WebkitAppearance!==q){n.appendChild(j);c=e.defaultView;c=c.getComputedStyle&&c.getComputedStyle(j,null).WebkitAppearance!=="textfield"&&j.offsetHeight!==0;n.removeChild(j)}else/^(search|tel)$/.test(j.type)||(c=/^(url|email)$/.test(j.type)?j.checkValidity&&j.checkValidity()===false:j.value!=L)}M[a[b]]=!!c}return M}("search tel url email datetime date month week time datetime-local number range color".split(" "))}var h={},n=e.documentElement,
N=e.head||e.getElementsByTagName("head")[0],F=e.createElement("modernizr"),k=F.style,j=e.createElement("input"),L=":)",O=Object.prototype.toString,t=" -webkit- -moz- -o- -ms- -khtml- ".split(" "),G="Webkit Moz O ms Khtml".split(" "),z={svg:"http://www.w3.org/2000/svg"},d={},M={},K={},P=[],A,Q=function(a){var b=e.createElement("style"),c=e.createElement("div");b.textContent=a+"{#modernizr{height:3px}}";N.appendChild(b);c.id="modernizr";n.appendChild(c);a=c.offsetHeight===3;b.parentNode.removeChild(b);
c.parentNode.removeChild(c);return!!a},H=function(){var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return function(b,c){c=c||e.createElement(a[b]||"div");b="on"+b;var i=b in c;if(!i){c.setAttribute||(c=e.createElement("div"));if(c.setAttribute&&c.removeAttribute){c.setAttribute(b,"");i=v(c[b],"function");v(c[b],q)||(c[b]=q);c.removeAttribute(b)}}return i}}(),I={}.hasOwnProperty,R;R=!v(I,q)&&!v(I.call,q)?function(a,b){return I.call(a,b)}:function(a,
b){return b in a&&v(a.constructor.prototype[b],q)};d.flexbox=function(){var a=e.createElement("div"),b=e.createElement("div");(function(i,g,p,w){g+=":";i.style.cssText=(g+t.join(p+";"+g)).slice(0,-g.length)+(w||"")})(a,"display","box","width:42px;padding:0;");b.style.cssText=t.join("box-flex:1;")+"width:10px;";a.appendChild(b);n.appendChild(a);var c=b.offsetWidth===42;a.removeChild(b);n.removeChild(a);return c};d.canvas=function(){var a=e.createElement("canvas");return!!(a.getContext&&a.getContext("2d"))};
d.canvastext=function(){return!!(h.canvas&&v(e.createElement("canvas").getContext("2d").fillText,"function"))};d.webgl=function(){var a=e.createElement("canvas");try{if(a.getContext("webgl"))return true}catch(b){}try{if(a.getContext("experimental-webgl"))return true}catch(c){}return false};d.touch=function(){return"ontouchstart"in l||Q("@media ("+t.join("touch-enabled),(")+"modernizr)")};d.geolocation=function(){return!!navigator.geolocation};d.postmessage=function(){return!!l.postMessage};d.websqldatabase=
function(){return!!l.openDatabase};d.indexedDB=function(){for(var a=-1,b=G.length;++a<b;){var c=G[a].toLowerCase();if(l[c+"_indexedDB"]||l[c+"IndexedDB"])return true}return false};d.hashchange=function(){return H("hashchange",l)&&(e.documentMode===q||e.documentMode>7)};d.history=function(){return!!(l.history&&history.pushState)};d.draganddrop=function(){return H("dragstart")&&H("drop")};d.websockets=function(){return"WebSocket"in l};d.rgba=function(){k.cssText="background-color:rgba(150,255,150,.5)";
return(""+k.backgroundColor).indexOf("rgba")!==-1};d.hsla=function(){k.cssText="background-color:hsla(120,40%,100%,.5)";return(""+k.backgroundColor).indexOf("rgba")!==-1||(""+k.backgroundColor).indexOf("hsla")!==-1};d.multiplebgs=function(){k.cssText="background:url(//:),url(//:),red url(//:)";return/(url\s*\(.*?){3}/.test(k.background)};d.backgroundsize=function(){return r("backgroundSize")};d.borderimage=function(){return r("borderImage")};d.borderradius=function(){return r("borderRadius","",function(a){return(""+
a).indexOf("orderRadius")!==-1})};d.boxshadow=function(){return r("boxShadow")};d.textshadow=function(){return e.createElement("div").style.textShadow===""};d.opacity=function(){var a=t.join("opacity:.55;")+"";k.cssText=a;return/^0.55$/.test(k.opacity)};d.cssanimations=function(){return r("animationName")};d.csscolumns=function(){return r("columnCount")};d.cssgradients=function(){var a=("background-image:"+t.join("gradient(linear,left top,right bottom,from(#9f9),to(white));background-image:")+t.join("linear-gradient(left top,#9f9, white);background-image:")).slice(0,
-17);k.cssText=a;return(""+k.backgroundImage).indexOf("gradient")!==-1};d.cssreflections=function(){return r("boxReflect")};d.csstransforms=function(){return!!E(["transformProperty","WebkitTransform","MozTransform","OTransform","msTransform"])};d.csstransforms3d=function(){var a=!!E(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);if(a&&"webkitPerspective"in n.style)a=Q("@media ("+t.join("transform-3d),(")+"modernizr)");return a};d.csstransitions=function(){return r("transitionProperty")};
d.fontface=function(){var a,b,c=N||n,i=e.createElement("style");b=e.implementation||{hasFeature:function(){return false}};i.type="text/css";c.insertBefore(i,c.firstChild);a=i.sheet||i.styleSheet;b=(b.hasFeature("CSS2","")?function(g){if(!(a&&g))return false;var p=false;try{a.insertRule(g,0);p=!/unknown/i.test(a.cssRules[0].cssText);a.deleteRule(a.cssRules.length-1)}catch(w){}return p}:function(g){if(!(a&&g))return false;a.cssText=g;return a.cssText.length!==0&&!/unknown/i.test(a.cssText)&&a.cssText.replace(/\r+|\n+/g,
"").indexOf(g.split(" ")[0])===0})('@font-face { font-family: "font"; src: "font.ttf"; }');c.removeChild(i);return b};d.video=function(){var a=e.createElement("video"),b=!!a.canPlayType;if(b){b=new Boolean(b);b.ogg=a.canPlayType('video/ogg; codecs="theora"');b.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"')||a.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');b.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"')}return b};d.audio=function(){var a=e.createElement("audio"),b=!!a.canPlayType;
if(b){b=new Boolean(b);b.ogg=a.canPlayType('audio/ogg; codecs="vorbis"');b.mp3=a.canPlayType("audio/mpeg;");b.wav=a.canPlayType('audio/wav; codecs="1"');b.m4a=a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")}return b};d.localstorage=function(){try{return!!localStorage.getItem}catch(a){return false}};d.sessionstorage=function(){try{return!!sessionStorage.getItem}catch(a){return false}};d.webWorkers=function(){return!!l.Worker};d.applicationcache=function(){return!!l.applicationCache};d.svg=
function(){return!!e.createElementNS&&!!e.createElementNS(z.svg,"svg").createSVGRect};d.inlinesvg=function(){var a=e.createElement("div");a.innerHTML="<svg/>";return(a.firstChild&&a.firstChild.namespaceURI)==z.svg};d.smil=function(){return!!e.createElementNS&&/SVG/.test(O.call(e.createElementNS(z.svg,"animate")))};d.svgclippaths=function(){return!!e.createElementNS&&/SVG/.test(O.call(e.createElementNS(z.svg,"clipPath")))};for(var J in d)if(R(d,J)){A=J.toLowerCase();h[A]=d[J]();P.push((h[A]?"":"no-")+
A)}h.input||V();h.crosswindowmessaging=h.postmessage;h.historymanagement=h.history;h.addTest=function(a,b){a=a.toLowerCase();if(!h[a]){b=!!b();n.className+=" "+(b?"":"no-")+a;h[a]=b;return h}};k.cssText="";F=f=null;l.attachEvent&&function(){var a=e.createElement("div");a.innerHTML="<elem></elem>";return a.childNodes.length!==1}()&&function(a,b){function c(s){for(var m=-1;++m<p;)s.createElement(g[m])}function i(s,m){for(var u=-1,o=s.length,B,S=[];++u<o;){B=s[u];if((m=B.media||m)!="screen")S.push(i(B.imports,
m),B.cssText)}return S.join("")}var g="abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video".split("|"),p=g.length,w=RegExp("(^|\\s)(abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video)","gi"),W=RegExp("<(/*)(abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video)",
"gi"),X=RegExp("(^|[^\\n]*?\\s)(abbr|article|aside|audio|canvas|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video)([^\\n]*)({[\\n\\w\\W]*?})","gi"),T=b.createDocumentFragment(),C=b.documentElement,U=C.firstChild,y=b.createElement("body"),D=b.createElement("style"),x;c(b);c(T);U.insertBefore(D,U.firstChild);D.media="print";a.attachEvent("onbeforeprint",function(){var s=-1,m=i(b.styleSheets,"all"),u=[],o;for(x=x||b.body;(o=X.exec(m))!=null;)u.push((o[1]+
o[2]+o[3]).replace(w,"$1.iepp_$2")+o[4]);for(D.styleSheet.cssText=u.join("\n");++s<p;){m=b.getElementsByTagName(g[s]);u=m.length;for(o=-1;++o<u;)if(m[o].className.indexOf("iepp_")<0)m[o].className+=" iepp_"+g[s]}T.appendChild(x);C.appendChild(y);y.className=x.className;y.innerHTML=x.innerHTML.replace(W,"<$1font")});a.attachEvent("onafterprint",function(){y.innerHTML="";C.removeChild(y);C.appendChild(x);D.styleSheet.cssText=""})}(l,e);h.shiv=function(){var a,b;return function(c,i){if(!a){a=e.createElement("div");
b=e.createDocumentFragment()}var g=a.cloneNode(true);g.innerHTML=c.replace(/^\s\s*/,"").replace(/\s\s*$/,"");if(i===false)return g.childNodes;for(var p=b.cloneNode(true),w=g.childNodes.length;w--;)p.appendChild(g.firstChild);return p}}();h._enableHTML5=true;h._version="1.6";n.className=n.className.replace(/\bno-js\b/,"")+" js";n.className+=" "+P.join(" ");return h}(this,this.document);
