/**
 * jQuery Masonry v2.0.110927
 * A dynamic layout plugin for jQuery
 * The flip-side of CSS Floats
 * http://masonry.desandro.com
 *
 * Licensed under the MIT license.
 * Copyright 2011 David DeSandro
 */
 
(function( window, $, undefined ){

  /*
   * smartresize: debounced resize event for jQuery
   *
   * latest version and complete README available on Github:
   * https://github.com/louisremi/jquery.smartresize.js
   *
   * Copyright 2011 @louis_remi
   * Licensed under the MIT license.
   */

  var $event = $.event,
      resizeTimeout;

  $event.special.smartresize = {
    setup: function() {
      $(this).bind( "resize", $event.special.smartresize.handler );
    },
    teardown: function() {
      $(this).unbind( "resize", $event.special.smartresize.handler );
    },
    handler: function( event, execAsap ) {
      // Save the context
      var context = this,
          args = arguments;

      // set correct event type
      event.type = "smartresize";

      if ( resizeTimeout ) { clearTimeout( resizeTimeout ); }
      resizeTimeout = setTimeout(function() {
        jQuery.event.handle.apply( context, args );
      }, execAsap === "execAsap"? 0 : 100 );
    }
  };

  $.fn.smartresize = function( fn ) {
    return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] );
  };



// ========================= Masonry ===============================
  // our "Widget" object constructor
  $.Mason = function( options, element ){
    this.element = $( element );

    this._create( options );
    this._init();
  };
  
  // styles of container element we want to keep track of
  var masonryContainerStyles = [ 'position', 'height' ];
  
  $.Mason.settings = {
    isResizable: true,
    isAnimated: false,
    animationOptions: {
      queue: false,
      duration: 500
    },
    gutterWidth: 0,
    isRTL: false,
    isFitWidth: false
  };

  $.Mason.prototype = {

    _filterFindBricks: function( $elems ) {
      var selector = this.options.itemSelector;
      // if there is a selector
      // filter/find appropriate item elements
      return !selector ? $elems : $elems.filter( selector ).add( $elems.find( selector ) );
    },

    _getBricks: function( $elems ) {
      var $bricks = this._filterFindBricks( $elems )
        .css({ position: 'absolute' })
        .addClass('masonry-brick');
      return $bricks;
    },
    
    // sets up widget
    _create : function( options ) {
      
      this.options = $.extend( true, {}, $.Mason.settings, options );
      
      this.styleQueue = [];
      // need to get bricks
      this.reloadItems();
	  
	  this.grid;

      // get original styles in case we re-apply them in .destroy()
      var elemStyle = this.element[0].style;
      this.originalStyle = {};
      for ( var i=0, len = masonryContainerStyles.length; i < len; i++ ) {
        var prop = masonryContainerStyles[i];
        this.originalStyle[ prop ] = elemStyle[ prop ] || '';
      }

      /*this.element.css({
        position : 'relative'
      });*/
      
      this.horizontalDirection = this.options.isRTL ? 'right' : 'left';
      this.offset = {};
      
      // get top left position of where the bricks should be
      var $cursor = $( document.createElement('div') );
      this.element.prepend( $cursor );
      this.offset.y = Math.round( $cursor.position().top );
      // get horizontal offset
      if ( !this.options.isRTL ) {
        this.offset.x = Math.round( $cursor.position().left );
      } else {
        $cursor.css({ 'float': 'right', display: 'inline-block'});
        this.offset.x = Math.round( this.element.outerWidth() - $cursor.position().left );
      }
      $cursor.remove();

      // add masonry class first time around
      var instance = this;
      setTimeout( function() {
        instance.element.addClass('masonry');
      }, 0 );
      
      // bind resize method
      if ( this.options.isResizable ) {
        $(window).bind( 'smartresize.masonry', function() { 
          instance.resize();
        });
      }
      
    },
  
    // _init fires when instance is first created
    // and when instance is triggered again -> $el.masonry();
    _init : function( callback ) {
      this._getColumns('masonry');
	  this._getRows('masonry');
      this._reLayout( callback );
    },

    option: function( key, value ){
      // set options AFTER initialization:
      // signature: $('#foo').bar({ cool:false });
      if ( $.isPlainObject( key ) ){
        this.options = $.extend(true, this.options, key);
      } 
    },
    
    // ====================== General Layout ======================

    // used on collection of atoms (should be filtered, and sorted before )
    // accepts atoms-to-be-laid-out to start with
    layout : function( $bricks, callback ) {
		
	  this._getGrid();

      // layout logic
      var $brick;
	  	  
	  var wSize = $(window).width();
	  var hSize = $(window).height();
	  
	  var allBoxes = new Array();
	  
	  var gridI = 0;
      for (var i=0, len = $bricks.length; i < len; i++) {
				  
		$brick = $( $bricks[i] );
		$brick.clearQueue(); //stop delay
		$brick.stop(true, true).hide();
		  
		var ratio = $brick.width()/$brick.height();
		$brick.ratio = ratio;
		
		//check if we need to skip to the next box?		
		//if( gridI>1 && !this._availRooom($brick, this.grid[gridI], wSize, hSize ) ) $brick.delay(i*250).fadeTo('slow', 0.5);
		//make the box smaller?
		
		//console.log("gridI=  " + gridI);
		while(this.grid[gridI]!=null 
				&& this.grid[gridI].width > 100 && this.grid[gridI].height > 100 
				&& !this._availRooom($brick, this.grid[gridI], wSize, hSize)){
			
			//reset		
			this.grid[gridI].x1 = null;
			this.grid[gridI].y1 = null;
			this.grid[gridI].x2 = null;
			this.grid[gridI].y2 = null;
			
			//if still offscreen, take the next
			if(this.grid[gridI].width <= 100 || this.grid[gridI].height <= 100 )  {
				//$brick.hide();
				gridI++;
			}
		}
		
		//console.log("gridI "+gridI+" fits!!");
		var currGrid = this.grid[gridI];
		if(currGrid != null) {
		
			//make sure the box fits
			var sizes = this._constrain( $brick, currGrid.width, currGrid.height);
			
			if(i==0){
				this.box0Width = parseInt(sizes.width);
				this.box0Height = parseInt(sizes.height);
			}
			
			//save for animation later, do not delete!
			$brick.data('width', sizes.width);
			$brick.data('height', sizes.height);
			$brick.data('top', -(sizes.height*1.1 - sizes.height)/2);
			$brick.data('left', -(sizes.width*1.1 - sizes.width)/2);			
			
			//align
			var position = this._align( $brick, currGrid, sizes, wSize, hSize);
			
			//save for later
			currGrid.x1 = position.left;
			currGrid.y1 = position.top;
			currGrid.x2 = position.left + sizes.width;
			currGrid.y2 = position.top + sizes.height;
			
			this.styleQueue.push({ $el: $brick, style: position });
			
			//animate 
			$brick.stop(true, true).delay(i*150).fadeIn("slow");
			//$brick.stop().fadeIn("slow");
			 
			gridI++;
			
		}
		
		//make the container as wide
		this.colYs[0] = wSize;
		
      }
	       
	  
      // are we animating the layout arrangement?
      // use plugin-ish syntax for css or animate
      var styleFn = !this.isLaidOut ? 'css' : (
            this.options.isAnimated ? 'animate' : 'css'
          ),
          animOpts = this.options.animationOptions;

      // process styleQueue
      var obj;
      for (i=0, len = this.styleQueue.length; i < len; i++) {
        obj = this.styleQueue[i];
        obj.$el[ styleFn ]( obj.style, animOpts );
      }

      // clear out queue for next time
      this.styleQueue = [];

      // provide $elems as context for the callback
      if ( callback ) {
        callback.call( $bricks );
      }
      
      this.isLaidOut = true;
	  
	  
	  homeTxtBlocks();
	  
    },
	
	
	 // calculates number of columns
    // i.e. this.columnWidth = 200
    _getGrid : function() {
	  
      this.grid = new Array(	    
		  {	  id: 1,
			  x: 0,
			  y: 0,
			  width: 550,
			  height: 400,
			  align: "LT"
		  },
		  {	  id: 2,
			  x: -200,
			  y: 175,
			  width: 175,
			  height: 225,
			  align: "RB"
		  },
		  {	  id: 3,
			  x: -200,
			  y: 0,
			  width: 175,
			  height: 150,
			  align: "RB",
			  alignTo: 2,
			  fromCorner: "RB",
			  toCorner: "RT"
		  },
		  {	  id: 4,
			  x: -200,
			  y: -227,
			  width: 175,
			  height: 200,
			  align: "RB",
			  alignTo: 3,
			  fromCorner: "RB",
			  toCorner: "RT"
		  },
		  {	  id: 5,
			  x: 0,
			  y: -252,
			  width: 500,
			  height: 225,
			  align: "LB",
			  alignTo: 1,
			  fromCorner: "LB",
			  toCorner: "LT"
		  },
		  {	  id: 6,
			  x: 526,
			  y: -227,
			  width: 225,
			  height: 200,
			  align: "LT",
			  alignTo: 5,
			  fromCorner: "LB",
			  toCorner: "RB"
		  },
		  {	  id: 7,
			  x: 576,
			  y: 0,
			  width: 175,
			  height: 150,
			  align: "LT",
			  alignTo: 1,
			  fromCorner: "LT",
			  toCorner: "RT"
		  },
		  {	  id: 8,
			  x: 576,
			  y: 175,
			  width: 175,
			  height: 225,
			  align: "RT",
			  alignTo: 1,
			  fromCorner: "LB",
			  toCorner: "RB"
		  },
		  {	  id: 9,
			  x: 576,
			  y: 425,
			  width: 175,
			  height: 175,
			  align: "RT",
			  alignTo: 8,
			  fromCorner: "LT",
			  toCorner: "LB"
		  },
		  {	  id: 10,
			  x: 400,
			  y: 425,
			  width: 150,
			  height: 175,
			  align: "LT",
			  alignTo: 1,
			  fromCorner: "RT",
			  toCorner: "RB"
		  },
		  {	  id: 11,
			  x: 0,
			  y: 425,
			  width: 150,
			  height: 175,
			  align: "LT",
			  alignTo: 10,
			  fromCorner: "RT",
			  toCorner: "LT"
		  },
		  {	  id: 12,
			  x: -300,
			  y: 425,
			  width: 275,
			  height: 175,
			  align: "RT",
			  alignTo: 11,
			  fromCorner: "RT",
			  toCorner: "LT"
		  },
		  {	  id: 13,
			  x: -425,
			  y: 150,
			  width: 200,
			  height: 250,
			  align: "RB",		
			  alignTo: 2,	 
			  fromCorner: "RB",
			  toCorner: "LB"
		  },
		  {	  id: 14,
			  x: -425,
			  y: -105,
			  width: 175,
			  height: 225,
			  align: "RB",
			  alignTo: 13, 
			  fromCorner: "LB",
			  toCorner: "LT"
		  },
		  {	  id: 15,
			  x: 275,
			  y: -429,
			  width: 225,
			  height: 150,
			  align: "RB",
			  alignTo: 5, 
			  fromCorner: "RB",
			  toCorner: "RT"
		  },
		  {	  id: 16,
			  x: 778,
			  y: -227,
			  width: 250,
			  height: 175,
			  align: "LB",
			  alignTo: 6,
			  fromCorner: "LB",
			  toCorner: "RB"
		  },
		  {	  id: 17,
			  x: 778,
			  y: -26,
			  width: 250,
			  height: 200,
			  align: "LT",
			  alignTo: 7,
			  fromCorner: "LT",
			  toCorner: "RT"
		  },
		  
		  {	  id: 18,
			  x: 778,
			  y: 199,
			  width: 250,
			  height: 175,
			  align: "LB",
			  alignTo: 8,
			  fromCorner: "LB",
			  toCorner: "RB"
		  },
		  {	  id: 19,
			  x: 803,
			  y: 424,
			  width: 225,
			  height: 150,
			  align: "LT",
			  alignTo: 9,
			  fromCorner: "LT",
			  toCorner: "RT"
		  },
		  {	  id: 20,
			  x: -625,
			  y: 425,
			  width: 300,
			  height: 175,
			  align: "RT",
			  alignTo: 12,
			  fromCorner: "RT",
			  toCorner: "LT"
		  },
		  {	  id: 21,
			  x: -676,
			  y: 150,
			  width: 225,
			  height: 250,
			  align: "LT",
			  alignTo: 13,
			  fromCorner: "RB",
			  toCorner: "LB"
		  },
		  {	  id: 22,
			  x: -676,
			  y: -100,
			  width: 225,
			  height: 225,
			  align: "LB",
			  alignTo: 21,
			  fromCorner: "RB",
			  toCorner: "RT"
		  },
		  {	  id: 23,
			  x: 1053,
			  y: -27,
			  width: 225,
			  height: 225,
			  align: "LB",
			  alignTo: 17,
			  fromCorner: "LT",
			  toCorner: "RT"
		  },
		  {	  id: 24,
			  x: 1053,
			  y: 224,
			  width: 225,
			  height: 225,
			  align: "LT",
			  alignTo: 23,
			  fromCorner: "LT",
			  toCorner: "LB"
		  }
	  );
    },
	
    
    // calculates number of columns
    // i.e. this.columnWidth = 200
    _getColumns : function() {
      var container = this.options.isFitWidth ? this.element.parent() : this.element,
          containerWidth = container.width();
      
      this.columnWidth = this.options.columnWidth ||
                    // or use the size of the first item
                    this.$bricks.outerWidth(true) ||
                    // if there's no items, use size of container
                    containerWidth;

      this.columnWidth += this.options.gutterWidth;

      this.cols = Math.floor( ( containerWidth + this.options.gutterWidth ) / this.columnWidth );
      this.cols = Math.max( this.cols, 1 );

    },
	
	_getRows : function() {
      var container = this.options.isFitHeight ? this.element.parent() : this.element,
          containerHeight = container.height();
      
      /*this.columnHeight = this.options.columnHeight ||
                    // or use the size of the first item
                    this.$bricks.outerHeight(true) ||
                    // if there's no items, use size of container
                    containerHeight;
		*/
      //this.columnHeight += this.options.gutterHeight;
	
      this.rows = Math.floor( containerHeight  / 100 );
      this.rows = Math.max( this.rows, 1 );

    },
	
	_constrain : function( $brick, maxW, maxH ) {
		
		var w = $brick.width;
		var h = $brick.height;
		
		if($brick.ratio >= 1){
			//console.log("**** landscape");
			w = maxW;
			h = maxW / $brick.ratio;
			
			if (h > maxH){
				h = maxH;
				w = maxH * $brick.ratio;
			}
			
		} else {
			//console.log("**** portrait");
			h = maxH;
			w = maxH * $brick.ratio;
			
			if(w > maxW){
				w = maxW;
				h = maxW / $brick.ratio;
			}
		}
		
	    var sizes = {
          width : w,
	 	  height: h
       };
		
	   this.styleQueue.push({ $el: $brick, style: sizes });
	   
	   return sizes;
    },
	
	_availRooom : function( $brick, currGrid, wSize, hSize ) {
		
		//console.log("check _availRooom for " + currGrid.id);
		
		var sizes = this._constrain( $brick, currGrid.width, currGrid.height);
			
		//save for animation later
		//align
		var position = this._align( $brick, currGrid, sizes, wSize, hSize);
		
		var x1 =  position.left;
		var x2 =  position.left + sizes.width;
		var y1 =  position.top;
		var y2 =  position.top + sizes.height;
		
		//_____________________fits on the window?
		if(x1 < 25){
			//adjust
			//currGrid.x += 10;
			currGrid.width -= 10;
			//currGrid.height -= 10;
			//console.log("doesnt fit LEFT try again");
			return false;			
		}
		else if ((x1  + currGrid.width + 25 ) > wSize ){
			//adjust
			currGrid.width -= 10;
			//currGrid.height -= 10;
			//console.log("doesnt fit RIGHT try again");
			return false;
		}
		else if (y1 < 25){
			//adjust
			currGrid.y += 10;
			//currGrid.width -= 10;
			currGrid.height -= 10;
			//console.log("doesnt fit TOP try again");
			return false;
		}
		else if ((y2 + 50) > hSize){
			//adjust
			//currGrid.width -= 10;
			currGrid.height -= 10;
			//console.log("doesnt fit BOTTOM try again");
			return false;
		}
		else if (x1 < 185 && y1 < 60) {
			//adjust
			currGrid.y += 10;
			currGrid.width -= 10;
			currGrid.height -= 10;
			//console.log("doesnt fit LOGO try again");
			return false;			
		}
		
		
		//console.log("currGrid.id=  " + currGrid.id);
		//console.log("y1=  " + y1);
		
		//_____________________fits on the window
		//_____________________check overlaps with previous		
		for (var g=0, len = currGrid.id; g < len; g++) {
			
			var pt = this.grid[g];
			//console.log("x1");
			//if((x1 < pt.x2 && x1 > pt.x1 && y2 > pt.y1 && y1 < pt.y2 ) || (x2 > pt.x1 && x1 < pt.x1  && y1 < pt.y2) ) {
			//if((x2 > pt.x1 && x1 < pt.x2 && y1 < pt.y2 && y2 > pt.y1 ) ) {	
			
			if ( x1 - 25 < pt.x2 && x2 + 25 > pt.x1 &&
               y1 - 25 < pt.y2 && y2 + 25 > pt.y1) {
				
				//console.log("OVERLAPPING");
				//$brick.delay(350).fadeTo('slow', 0.5);
				currGrid.width -= 10;
				currGrid.height -= 10;
				return false;
			}
		}
		
		
		/*if((x1 < 25 || 
			(x1  + currGrid.width) > wSize || 
				y1 < 25 || 
					(y2 + 40) > hSize) || (x1 < 185 && y1 < 60)  ) {
						
						
						//adjust
						currGrid.width -= 10;
						currGrid.height -= 10;
						console.log("doesnt fit * try again");
						return false;
					} 
		*/			
		//not overlapping?
		//loop through all the positions and check
		//if(x) return false;
		
		
					
		return true;
    },
	
	
	_align : function($box, currGrid, sizes, wSize, hSize){
		
		var left = currGrid.x;
		var top = currGrid.y;
		
		var firstBox = this.grid[0];
		var correctX = (wSize-this.box0Width)/2;
		var correctY = (hSize-400)/2;
		//var correctX = (wSize-375)/2;
		//var correctY = (hSize-400)/2;
		
		
		switch (currGrid.align){
			case "LT":			 			
			default:
				break;
			case "RT":
				left += currGrid.width - sizes.width;
				break;
			case "LB":
				top += currGrid.height - sizes.height;
				break;
			case "RB": 			
				top += currGrid.height - sizes.height;
				left += currGrid.width - sizes.width;
				break;
		}
		
		
		//alignTo
		if(currGrid.alignTo != null){
			var alignTo = this.grid[currGrid.alignTo-1];
			//console.log("currGrid.align2="  + currGrid.align2);
			
			//console.log("\ncurrGrid="  +currGrid.id);
			
			//split
			var toChars = currGrid.toCorner.split("");
			var toLR = (toChars[0]=="L")? alignTo.x1:alignTo.x2;
			var toTB = (toChars[1]=="T")? alignTo.y1:alignTo.y2;
			
			//if(toLR == undefined) toLR = alignTo.x - correctX;
			//if(toTB == undefined) toTB = alignTo.y - correctY;
			
			if(toLR == undefined) {
				var position = {
					left: left + correctX,
					top: top + correctY
				}
				return position;
			}
			
			var fromChars = currGrid.fromCorner.split("");
			
			if(fromChars[0]=="R" && toChars[0]=="R") {
				toLR -= sizes.width;
			} else if (fromChars[0]=="L" && toChars[0]=="R") {
				toLR += 25;
			} else if (fromChars[0]=="R" && toChars[0]=="L") {
				toLR -= sizes.width + 25;
			}
			
			if(fromChars[1]=="B" ) toTB -= sizes.height;
			if(fromChars[1]=="B" && toChars[1]=="T") toTB -=  25;
			
			if(fromChars[1]=="T" && toChars[1]=="B") toTB +=  25;
			 
			//adjust
			left  =  toLR - correctX;
			top  = toTB - correctY;
		
			//console.log("toChars[1]="  + toChars[1]);
			//console.log("fromChars[1]="  + fromChars[1]);
		}

		var position = {
			left: left + correctX,
			top: top + correctY
		}
		
		return position;
	},
    
    resize : function() {
      var prevColCount = this.cols;
	  var prevRowCount = this.rows;
	  //console.log("prevRowCount="  +prevRowCount);
      // get updated colCount
      this._getColumns('masonry');
	  this._getRows('masonry');
	  
      if ( this.cols !== prevColCount || this.rows !== prevRowCount ) {
        // if column count has changed, trigger new layout
        this._reLayout();
      }
    },
    
    
    _reLayout : function( callback ) {
      // reset columns
      var i = this.cols;
      this.colYs = [];
      while (i--) {
        this.colYs.push( this.offset.y );
      }
      // apply layout logic to all bricks
      this.layout( this.$bricks, callback );
    },
    
    // ====================== Convenience methods ======================
    
    // goes through all children again and gets bricks in proper order
    reloadItems : function() {
      this.$bricks = this._getBricks( this.element.children() );
    },
    
    
    reload : function( callback ) {
      this.reloadItems();
      this._init( callback );
    },
    

    // convienence method for working with Infinite Scroll
    appended : function( $content, isAnimatedFromBottom, callback ) {
      if ( isAnimatedFromBottom ) {
        // set new stuff to the bottom
        this._filterFindBricks( $content ).css({ top: this.element.height() });
        var instance = this;
        setTimeout( function(){
          instance._appended( $content, callback );
        }, 1 );
      } else {
        this._appended( $content, callback );
      }
    },
    
    _appended : function( $content, callback ) {
      var $newBricks = this._getBricks( $content );
      // add new bricks to brick pool
      this.$bricks = this.$bricks.add( $newBricks );
      this.layout( $newBricks, callback );
    },
    
    // removes elements from Masonry widget
    remove : function( $content ) {
      this.$bricks = this.$bricks.not( $content );
      $content.remove();
    },
    
    // destroys widget, returns elements and container back (close) to original style
    destroy : function() {

      this.$bricks
        .removeClass('masonry-brick')
        .each(function(){
          this.style.position = '';
          this.style.top = '';
          this.style.left = '';
        });
      
      // re-apply saved container styles
      var elemStyle = this.element[0].style;
      for ( var i=0, len = masonryContainerStyles.length; i < len; i++ ) {
        var prop = masonryContainerStyles[i];
        elemStyle[ prop ] = this.originalStyle[ prop ];
      }
      
      this.element
        .unbind('.masonry')
        .removeClass('masonry')
        .removeData('masonry');
      
      $(window).unbind('.masonry');

    }
    
  };
  
  
  // ======================= imagesLoaded Plugin ===============================
  /*!
   * jQuery imagesLoaded plugin v1.0.3
   * http://github.com/desandro/imagesloaded
   *
   * MIT License. by Paul Irish et al.
   */


  // $('#my-container').imagesLoaded(myFunction)
  // or
  // $('img').imagesLoaded(myFunction)

  // execute a callback when all images have loaded.
  // needed because .load() doesn't work on cached images

  // callback function gets image collection as argument
  //  `this` is the container

  $.fn.imagesLoaded = function( callback ) {
    var $this = this,
        $images = $this.find('img').add( $this.filter('img') ),
        len = $images.length,
        blank = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';

    function triggerCallback() {
      callback.call( $this, $images );
    }

    function imgLoaded() {
      if ( --len <= 0 && this.src !== blank ){
        setTimeout( triggerCallback );
        $images.unbind( 'load error', imgLoaded );
      }
    }

    if ( !len ) {
      triggerCallback();
    }

    $images.bind( 'load error',  imgLoaded ).each( function() {
      // cached images don't fire load sometimes, so we reset src.
      if (this.complete || this.complete === undefined){
        var src = this.src;
        // webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
        // data uri bypasses webkit log warning (thx doug jones)
        this.src = blank;
        this.src = src;
      }
    });

    return $this;
  };


  // helper function for logging errors
  // $.error breaks jQuery chaining
  var logError = function( message ) {
    if ( this.console ) {
      console.error( message );
    }
  };
  
  // =======================  Plugin bridge  ===============================
  // leverages data method to either create or return $.Mason constructor
  // A bit from jQuery UI
  //   https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js
  // A bit from jcarousel 
  //   https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js

  $.fn.masonry = function( options ) {
    if ( typeof options === 'string' ) {
      // call method
      var args = Array.prototype.slice.call( arguments, 1 );

      this.each(function(){
        var instance = $.data( this, 'masonry' );
        if ( !instance ) {
          logError( "cannot call methods on masonry prior to initialization; " +
            "attempted to call method '" + options + "'" );
          return;
        }
        if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
          logError( "no such method '" + options + "' for masonry instance" );
          return;
        }
        // apply method
        instance[ options ].apply( instance, args );
      });
    } else {
      this.each(function() {
        var instance = $.data( this, 'masonry' );
        if ( instance ) {
          // apply options & init
          instance.option( options || {} );
          instance._init();
        } else {
          // initialize new instance
          $.data( this, 'masonry', new $.Mason( options, this ) );
        }
      });
    }
    return this;
  };

})( window, jQuery );

