text: /*!
   * Isotope v2.0.0
   * Filter & sort magical layouts
   * http://isotope.metafizzy.co
   */
  
  ( function( window ) {
  
  'use strict';
  
  // -------------------------- vars -------------------------- //
  
  var jQuery = window.jQuery;
  
  // -------------------------- helpers -------------------------- //
  
  // extend objects
  function extend( a, b ) {
    for ( var prop in b ) {
      a[ prop ] = b[ prop ];
    }
    return a;
  }
  
  var trim = String.prototype.trim ?
    function( str ) {
      return str.trim();
    } :
    function( str ) {
      return str.replace( /^\s+|\s+$/g, '' );
    };
  
  var docElem = document.documentElement;
  
  var getText = docElem.textContent ?
    function( elem ) {
      return elem.textContent;
    } :
    function( elem ) {
      return elem.innerText;
    };
  
  var objToString = Object.prototype.toString;
  function isArray( obj ) {
    return objToString.call( obj ) === '[object Array]';
  }
  
  // index of helper cause IE8
  var indexOf = Array.prototype.indexOf ? function( ary, obj ) {
      return ary.indexOf( obj );
    } : function( ary, obj ) {
      for ( var i=0, len = ary.length; i < len; i++ ) {
        if ( ary[i] === obj ) {
          return i;
        }
      }
      return -1;
    };
  
  // turn element or nodeList into an array
  function makeArray( obj ) {
    var ary = [];
    if ( isArray( obj ) ) {
      // use object if already an array
      ary = obj;
    } else if ( obj && typeof obj.length === 'number' ) {
      // convert nodeList to array
      for ( var i=0, len = obj.length; i < len; i++ ) {
        ary.push( obj[i] );
      }
    } else {
      // array of single index
      ary.push( obj );
    }
    return ary;
  }
  
  function removeFrom( obj, ary ) {
    var index = indexOf( ary, obj );
    if ( index !== -1 ) {
      ary.splice( index, 1 );
    }
  }
  
  // -------------------------- isotopeDefinition -------------------------- //
  
  // used for AMD definition and requires
  function isotopeDefinition( Outlayer, getSize, matchesSelector, Item, LayoutMode ) {
    // create an Outlayer layout class
    var Isotope = Outlayer.create( 'isotope', {
      layoutMode: "masonry",
      isJQueryFiltering: true,
      sortAscending: true
    });
  
    Isotope.Item = Item;
    Isotope.LayoutMode = LayoutMode;
  
    Isotope.prototype._create = function() {
      this.itemGUID = 0;
      // functions that sort items
      this._sorters = {};
      this._getSorters();
      // call super
      Outlayer.prototype._create.call( this );
  
      // create layout modes
      this.modes = {};
      // start filteredItems with all items
      this.filteredItems = this.items;
      // keep of track of sortBys
      this.sortHistory = [ 'original-order' ];
      // create from registered layout modes
      for ( var name in LayoutMode.modes ) {
        this._initLayoutMode( name );
      }
    };
  
    Isotope.prototype.reloadItems = function() {
      // reset item ID counter
      this.itemGUID = 0;
      // call super
      Outlayer.prototype.reloadItems.call( this );
    };
  
    Isotope.prototype._itemize = function() {
      var items = Outlayer.prototype._itemize.apply( this, arguments );
      // assign ID for original-order
      for ( var i=0, len = items.length; i < len; i++ ) {
        var item = items[i];
        item.id = this.itemGUID++;
      }
      this._updateItemsSortData( items );
      return items;
    };
  
  
    // -------------------------- layout -------------------------- //
  
    Isotope.prototype._initLayoutMode = function( name ) {
      var Mode = LayoutMode.modes[ name ];
      // set mode options
      // HACK extend initial options, back-fill in default options
      var initialOpts = this.options[ name ] || {};
      this.options[ name ] = Mode.options ?
        extend( Mode.options, initialOpts ) : initialOpts;
      // init layout mode instance
      this.modes[ name ] = new Mode( this );
    };
  
  
    Isotope.prototype.layout = function() {
      // if first time doing layout, do all magic
      if ( !this._isLayoutInited && this.options.isInitLayout ) {
        this.arrange();
        return;
      }
      this._layout();
    };
  
    // private method to be used in layout() & magic()
    Isotope.prototype._layout = function() {
      // don't animate first layout
      var isInstant = this._getIsInstant();
      // layout flow
      this._resetLayout();
      this._manageStamps();
      this.layoutItems( this.filteredItems, isInstant );
  
      // flag for initalized
      this._isLayoutInited = true;
    };
  
    // filter + sort + layout
    Isotope.prototype.arrange = function( opts ) {
      // set any options pass
      this.option( opts );
      this._getIsInstant();
      // filter, sort, and layout
      this.filteredItems = this._filter( this.items );
      this._sort();
      this._layout();
    };
    // alias to _init for main plugin method
    Isotope.prototype._init = Isotope.prototype.arrange;
  
    // HACK
    // Don't animate/transition first layout
    // Or don't animate/transition other layouts
    Isotope.prototype._getIsInstant = function() {
      var isInstant = this.options.isLayoutInstant !== undefined ?
        this.options.isLayoutInstant : !this._isLayoutInited;
      this._isInstant = isInstant;
      return isInstant;
    };
  
    // -------------------------- filter -------------------------- //
  
    Isotope.prototype._filter = function( items ) {
      var filter = this.options.filter;
      filter = filter || '*';
      var matches = [];
      var hiddenMatched = [];
      var visibleUnmatched = [];
  
      var test = this._getFilterTest( filter );
  
      // test each item
      for ( var i=0, len = items.length; i < len; i++ ) {
        var item = items[i];
        if ( item.isIgnored ) {
          continue;
        }
        // add item to either matched or unmatched group
        var isMatched = test( item );
        // item.isFilterMatched = isMatched;
        // add to matches if its a match
        if ( isMatched ) {
          matches.push( item );
        }
        // add to additional group if item needs to be hidden or revealed
        if ( isMatched && item.isHidden ) {
          hiddenMatched.push( item );
        } else if ( !isMatched && !item.isHidden ) {
          visibleUnmatched.push( item );
        }
      }
  
      var _this = this;
      function hideReveal() {
        _this.reveal( hiddenMatched );
        _this.hide( visibleUnmatched );
      }
  
      if ( this._isInstant ) {
        this._noTransition( hideReveal );
      } else {
        hideReveal();
      }
  
      return matches;
    };
  
    // get a jQuery, function, or a matchesSelector test given the filter
    Isotope.prototype._getFilterTest = function( filter ) {
      if ( jQuery && this.options.isJQueryFiltering ) {
        // use jQuery
        return function( item ) {
          return jQuery( item.element ).is( filter );
        };
      }
      if ( typeof filter === 'function' ) {
        // use filter as function
        return function( item ) {
          return filter( item.element );
        };
      }
      // default, use filter as selector string
      return function( item ) {
        return matchesSelector( item.element, filter );
      };
    };
  
    // -------------------------- sorting -------------------------- //
  
    /**
     * @params {Array} elems
     * @public
     */
    Isotope.prototype.updateSortData = function( elems ) {
      this._getSorters();
      // update item sort data
      // default to all items if none are passed in
      elems = makeArray( elems );
      var items = this.getItems( elems );
      // if no items found, update all items
      items = items.length ? items : this.items;
      this._updateItemsSortData( items );
    };
  
    Isotope.prototype._getSorters = function() {
      var getSortData = this.options.getSortData;
      for ( var key in getSortData ) {
        var sorter = getSortData[ key ];
        this._sorters[ key ] = mungeSorter( sorter );
      }
    };
  
    /**
     * @params {Array} items - of Isotope.Items
     * @private
     */
    Isotope.prototype._updateItemsSortData = function( items ) {
      for ( var i=0, len = items.length; i < len; i++ ) {
        var item = items[i];
        item.updateSortData();
      }
    };
  
    // ----- munge sorter ----- //
  
    // encapsulate this, as we just need mungeSorter
    // other functions in here are just for munging
    var mungeSorter = ( function() {
      // add a magic layer to sorters for convienent shorthands
      // `.foo-bar` will use the text of .foo-bar querySelector
      // `[foo-bar]` will use attribute
      // you can also add parser
      // `.foo-bar parseInt` will parse that as a number
      function mungeSorter( sorter ) {
        // if not a string, return function or whatever it is
        if ( typeof sorter !== 'string' ) {
          return sorter;
        }
        // parse the sorter string
        var args = trim( sorter ).split(' ');
        var query = args[0];
        // check if query looks like [an-attribute]
        var attrMatch = query.match( /^\[(.+)\]$/ );
        var attr = attrMatch && attrMatch[1];
        var getValue = getValueGetter( attr, query );
        // use second argument as a parser
        var parser = Isotope.sortDataParsers[ args[1] ];
        // parse the value, if there was a parser
        sorter = parser ? function( elem ) {
          return elem && parser( getValue( elem ) );
        } :
        // otherwise just return value
        function( elem ) {
          return elem && getValue( elem );
        };
  
        return sorter;
      }
  
      // get an attribute getter, or get text of the querySelector
      function getValueGetter( attr, query ) {
        var getValue;
        // if query looks like [foo-bar], get attribute
        if ( attr ) {
          getValue = function( elem ) {
            return elem.getAttribute( attr );
          };
        } else {
          // otherwise, assume its a querySelector, and get its text
          getValue = function( elem ) {
            var child = elem.querySelector( query );
            return child && getText( child );
          };
        }
        return getValue;
      }
  
      return mungeSorter;
    })();
  
    // parsers used in getSortData shortcut strings
    Isotope.sortDataParsers = {
      'parseInt': function( val ) {
        return parseInt( val, 10 );
      },
      'parseFloat': function( val ) {
        return parseFloat( val );
      }
    };
  
    // ----- sort method ----- //
  
    // sort filteredItem order
    Isotope.prototype._sort = function() {
      var sortByOpt = this.options.sortBy;
      if ( !sortByOpt ) {
        return;
      }
      // concat all sortBy and sortHistory
      var sortBys = [].concat.apply( sortByOpt, this.sortHistory );
      // sort magic
      var itemSorter = getItemSorter( sortBys, this.options.sortAscending );
      this.filteredItems.sort( itemSorter );
      // keep track of sortBy History
      if ( sortByOpt !== this.sortHistory[0] ) {
        // add to front, oldest goes in last
        this.sortHistory.unshift( sortByOpt );
      }
    };
  
    // returns a function used for sorting
    function getItemSorter( sortBys, sortAsc ) {
      return function sorter( itemA, itemB ) {
        // cycle through all sortKeys
        for ( var i = 0, len = sortBys.length; i < len; i++ ) {
          var sortBy = sortBys[i];
          var a = itemA.sortData[ sortBy ];
          var b = itemB.sortData[ sortBy ];
          if ( a > b || a < b ) {
            // if sortAsc is an object, use the value given the sortBy key
            var isAscending = sortAsc[ sortBy ] !== undefined ? sortAsc[ sortBy ] : sortAsc;
            var direction = isAscending ? 1 : -1;
            return ( a > b ? 1 : -1 ) * direction;
          }
        }
        return 0;
      };
    }
  
    // -------------------------- methods -------------------------- //
  
    // get layout mode
    Isotope.prototype._mode = function() {
      var layoutMode = this.options.layoutMode;
      var mode = this.modes[ layoutMode ];
      if ( !mode ) {
        // TODO console.error
        throw new Error( 'No layout mode: ' + layoutMode );
      }
      // HACK sync mode's options
      // any options set after init for layout mode need to be synced
      mode.options = this.options[ layoutMode ];
      return mode;
    };
  
    Isotope.prototype._resetLayout = function() {
      // trigger original reset layout
      Outlayer.prototype._resetLayout.call( this );
      this._mode()._resetLayout();
    };
  
    Isotope.prototype._getItemLayoutPosition = function( item  ) {
      return this._mode()._getItemLayoutPosition( item );
    };
  
    Isotope.prototype._manageStamp = function( stamp ) {
      this._mode()._manageStamp( stamp );
    };
  
    Isotope.prototype._getContainerSize = function() {
      return this._mode()._getContainerSize();
    };
  
    Isotope.prototype.needsResizeLayout = function() {
      return this._mode().needsResizeLayout();
    };
  
    // -------------------------- adding & removing -------------------------- //
  
    // HEADS UP overwrites default Outlayer appended
    Isotope.prototype.appended = function( elems ) {
      var items = this.addItems( elems );
      if ( !items.length ) {
        return;
      }
      var filteredItems = this._filterRevealAdded( items );
      // add to filteredItems
      this.filteredItems = this.filteredItems.concat( filteredItems );
    };
  
    // HEADS UP overwrites default Outlayer prepended
    Isotope.prototype.prepended = function( elems ) {
      var items = this._itemize( elems );
      if ( !items.length ) {
        return;
      }
      // add items to beginning of collection
      var previousItems = this.items.slice(0);
      this.items = items.concat( previousItems );
      // start new layout
      this._resetLayout();
      this._manageStamps();
      // layout new stuff without transition
      var filteredItems = this._filterRevealAdded( items );
      // layout previous items
      this.layoutItems( previousItems );
      // add to filteredItems
      this.filteredItems = filteredItems.concat( this.filteredItems );
    };
  
    Isotope.prototype._filterRevealAdded = function( items ) {
      var filteredItems = this._noTransition( function() {
        return this._filter( items );
      });
      // layout and reveal just the new items
      this.layoutItems( filteredItems, true );
      this.reveal( filteredItems );
      return items;
    };
  
    /**
     * Filter, sort, and layout newly-appended item elements
     * @param {Array or NodeList or Element} elems
     */
    Isotope.prototype.insert = function( elems ) {
      var items = this.addItems( elems );
      if ( !items.length ) {
        return;
      }
      // append item elements
      var i, item;
      var len = items.length;
      for ( i=0; i < len; i++ ) {
        item = items[i];
        this.element.appendChild( item.element );
      }
      // filter new stuff
      /*
      // this way adds hides new filtered items with NO transition
      // so user can't see if new hidden items have been inserted
      var filteredInsertItems;
      this._noTransition( function() {
        filteredInsertItems = this._filter( items );
        // hide all new items
        this.hide( filteredInsertItems );
      });
      // */
      // this way hides new filtered items with transition
      // so user at least sees that something has been added
      var filteredInsertItems = this._filter( items );
      // hide all newitems
      this._noTransition( function() {
        this.hide( filteredInsertItems );
      });
      // */
      // set flag
      for ( i=0; i < len; i++ ) {
        items[i].isLayoutInstant = true;
      }
      this.arrange();
      // reset flag
      for ( i=0; i < len; i++ ) {
        delete items[i].isLayoutInstant;
      }
      this.reveal( filteredInsertItems );
    };
  
    var _remove = Isotope.prototype.remove;
    Isotope.prototype.remove = function( elems ) {
      elems = makeArray( elems );
      var removeItems = this.getItems( elems );
      // do regular thing
      _remove.call( this, elems );
      // bail if no items to remove
      if ( !removeItems || !removeItems.length ) {
        return;
      }
      // remove elems from filteredItems
      for ( var i=0, len = removeItems.length; i < len; i++ ) {
        var item = removeItems[i];
        // remove item from collection
        removeFrom( item, this.filteredItems );
      }
    };
  
    /**
     * trigger fn without transition
     * kind of hacky to have this in the first place
     * @param {Function} fn
     * @returns ret
     * @private
     */
    Isotope.prototype._noTransition = function( fn ) {
      // save transitionDuration before disabling
      var transitionDuration = this.options.transitionDuration;
      // disable transition
      this.options.transitionDuration = 0;
      // do it
      var returnValue = fn.call( this );
      // re-enable transition for reveal
      this.options.transitionDuration = transitionDuration;
      return returnValue;
    };
  
    // -----  ----- //
  
    return Isotope;
  }
  
  // -------------------------- transport -------------------------- //
  
  if ( typeof define === 'function' && define.amd ) {
    // AMD
    define( [
        'outlayer/outlayer',
        'get-size/get-size',
        'matches-selector/matches-selector',
        './item',
        './layout-mode',
        // include default layout modes
        './layout-modes/masonry',
        './layout-modes/fit-rows',
        './layout-modes/vertical'
      ],
      isotopeDefinition );
  } else {
    // browser global
    window.Isotope = isotopeDefinition(
      window.Outlayer,
      window.getSize,
      window.matchesSelector,
      window.Isotope.Item,
      window.Isotope.LayoutMode
    );
  }
  
  })( window );
  