!function($) {

“use strict”;

var FOUNDATION_VERSION = ‘6.3.1’;

// Global Foundation object // This is attached to the window, or used as a module for AMD/Browserify var Foundation = {

version: FOUNDATION_VERSION,

/**
 * Stores initialized plugins.
 */
_plugins: {},

/**
 * Stores generated unique ids for plugin instances
 */
_uuids: [],

/**
 * Returns a boolean for RTL support
 */
rtl: function(){
  return $('html').attr('dir') === 'rtl';
},
/**
 * Defines a Foundation plugin, adding it to the `Foundation` namespace and the list of plugins to initialize when reflowing.
 * @param {Object} plugin - The constructor of the plugin.
 */
plugin: function(plugin, name) {
  // Object key to use when adding to global Foundation object
  // Examples: Foundation.Reveal, Foundation.OffCanvas
  var className = (name || functionName(plugin));
  // Object key to use when storing the plugin, also used to create the identifying data attribute for the plugin
  // Examples: data-reveal, data-off-canvas
  var attrName  = hyphenate(className);

  // Add to the Foundation object and the plugins list (for reflowing)
  this._plugins[attrName] = this[className] = plugin;
},
/**
 * @function
 * Populates the _uuids array with pointers to each individual plugin instance.
 * Adds the `zfPlugin` data-attribute to programmatically created plugins to allow use of $(selector).foundation(method) calls.
 * Also fires the initialization event for each plugin, consolidating repetitive code.
 * @param {Object} plugin - an instance of a plugin, usually `this` in context.
 * @param {String} name - the name of the plugin, passed as a camelCased string.
 * @fires Plugin#init
 */
registerPlugin: function(plugin, name){
  var pluginName = name ? hyphenate(name) : functionName(plugin.constructor).toLowerCase();
  plugin.uuid = this.GetYoDigits(6, pluginName);

  if(!plugin.$element.attr(`data-${pluginName}`)){ plugin.$element.attr(`data-${pluginName}`, plugin.uuid); }
  if(!plugin.$element.data('zfPlugin')){ plugin.$element.data('zfPlugin', plugin); }
        /**
         * Fires when the plugin has initialized.
         * @event Plugin#init
         */
  plugin.$element.trigger(`init.zf.${pluginName}`);

  this._uuids.push(plugin.uuid);

  return;
},
/**
 * @function
 * Removes the plugins uuid from the _uuids array.
 * Removes the zfPlugin data attribute, as well as the data-plugin-name attribute.
 * Also fires the destroyed event for the plugin, consolidating repetitive code.
 * @param {Object} plugin - an instance of a plugin, usually `this` in context.
 * @fires Plugin#destroyed
 */
unregisterPlugin: function(plugin){
  var pluginName = hyphenate(functionName(plugin.$element.data('zfPlugin').constructor));

  this._uuids.splice(this._uuids.indexOf(plugin.uuid), 1);
  plugin.$element.removeAttr(`data-${pluginName}`).removeData('zfPlugin')
        /**
         * Fires when the plugin has been destroyed.
         * @event Plugin#destroyed
         */
        .trigger(`destroyed.zf.${pluginName}`);
  for(var prop in plugin){
    plugin[prop] = null;//clean up script to prep for garbage collection.
  }
  return;
},

/**
 * @function
 * Causes one or more active plugins to re-initialize, resetting event listeners, recalculating positions, etc.
 * @param {String} plugins - optional string of an individual plugin key, attained by calling `$(element).data('pluginName')`, or string of a plugin class i.e. `'dropdown'`
 * @default If no argument is passed, reflow all currently active plugins.
 */
 reInit: function(plugins){
   var isJQ = plugins instanceof $;
   try{
     if(isJQ){
       plugins.each(function(){
         $(this).data('zfPlugin')._init();
       });
     }else{
       var type = typeof plugins,
       _this = this,
       fns = {
         'object': function(plgs){
           plgs.forEach(function(p){
             p = hyphenate(p);
             $('[data-'+ p +']').foundation('_init');
           });
         },
         'string': function(){
           plugins = hyphenate(plugins);
           $('[data-'+ plugins +']').foundation('_init');
         },
         'undefined': function(){
           this['object'](Object.keys(_this._plugins));
         }
       };
       fns[type](plugins);
     }
   }catch(err){
     console.error(err);
   }finally{
     return plugins;
   }
 },

/**
 * returns a random base-36 uid with namespacing
 * @function
 * @param {Number} length - number of random base-36 digits desired. Increase for more random strings.
 * @param {String} namespace - name of plugin to be incorporated in uid, optional.
 * @default {String} '' - if no plugin name is provided, nothing is appended to the uid.
 * @returns {String} - unique id
 */
GetYoDigits: function(length, namespace){
  length = length || 6;
  return Math.round((Math.pow(36, length + 1) - Math.random() * Math.pow(36, length))).toString(36).slice(1) + (namespace ? `-${namespace}` : '');
},
/**
 * Initialize plugins on any elements within `elem` (and `elem` itself) that aren't already initialized.
 * @param {Object} elem - jQuery object containing the element to check inside. Also checks the element itself, unless it's the `document` object.
 * @param {String|Array} plugins - A list of plugins to initialize. Leave this out to initialize everything.
 */
reflow: function(elem, plugins) {

  // If plugins is undefined, just grab everything
  if (typeof plugins === 'undefined') {
    plugins = Object.keys(this._plugins);
  }
  // If plugins is a string, convert it to an array with one item
  else if (typeof plugins === 'string') {
    plugins = [plugins];
  }

  var _this = this;

  // Iterate through each plugin
  $.each(plugins, function(i, name) {
    // Get the current plugin
    var plugin = _this._plugins[name];

    // Localize the search to all elements inside elem, as well as elem itself, unless elem === document
    var $elem = $(elem).find('[data-'+name+']').addBack('[data-'+name+']');

    // For each plugin found, initialize it
    $elem.each(function() {
      var $el = $(this),
          opts = {};
      // Don't double-dip on plugins
      if ($el.data('zfPlugin')) {
        console.warn("Tried to initialize "+name+" on an element that already has a Foundation plugin.");
        return;
      }

      if($el.attr('data-options')){
        var thing = $el.attr('data-options').split(';').forEach(function(e, i){
          var opt = e.split(':').map(function(el){ return el.trim(); });
          if(opt[0]) opts[opt[0]] = parseValue(opt[1]);
        });
      }
      try{
        $el.data('zfPlugin', new plugin($(this), opts));
      }catch(er){
        console.error(er);
      }finally{
        return;
      }
    });
  });
},
getFnName: functionName,
transitionend: function($elem){
  var transitions = {
    'transition': 'transitionend',
    'WebkitTransition': 'webkitTransitionEnd',
    'MozTransition': 'transitionend',
    'OTransition': 'otransitionend'
  };
  var elem = document.createElement('div'),
      end;

  for (var t in transitions){
    if (typeof elem.style[t] !== 'undefined'){
      end = transitions[t];
    }
  }
  if(end){
    return end;
  }else{
    end = setTimeout(function(){
      $elem.triggerHandler('transitionend', [$elem]);
    }, 1);
    return 'transitionend';
  }
}

};

Foundation.util = {

/**
 * Function for applying a debounce effect to a function call.
 * @function
 * @param {Function} func - Function to be called at end of timeout.
 * @param {Number} delay - Time in ms to delay the call of `func`.
 * @returns function
 */
throttle: function (func, delay) {
  var timer = null;

  return function () {
    var context = this, args = arguments;

    if (timer === null) {
      timer = setTimeout(function () {
        func.apply(context, args);
        timer = null;
      }, delay);
    }
  };
}

};

// TODO: consider not making this a jQuery function // TODO: need way to reflow vs. re-initialize /**

* The Foundation jQuery method.
* @param {String|Array} method - An action to perform on the current jQuery object.
*/

var foundation = function(method) {

var type = typeof method,
    $meta = $('meta.foundation-mq'),
    $noJS = $('.no-js');

if(!$meta.length){
  $('<meta class="foundation-mq">').appendTo(document.head);
}
if($noJS.length){
  $noJS.removeClass('no-js');
}

if(type === 'undefined'){//needs to initialize the Foundation object, or an individual plugin.
  Foundation.MediaQuery._init();
  Foundation.reflow(this);
}else if(type === 'string'){//an individual method to invoke on a plugin or group of plugins
  var args = Array.prototype.slice.call(arguments, 1);//collect all the arguments, if necessary
  var plugClass = this.data('zfPlugin');//determine the class of plugin

  if(plugClass !== undefined && plugClass[method] !== undefined){//make sure both the class and method exist
    if(this.length === 1){//if there's only one, call it directly.
        plugClass[method].apply(plugClass, args);
    }else{
      this.each(function(i, el){//otherwise loop through the jQuery collection and invoke the method on each
        plugClass[method].apply($(el).data('zfPlugin'), args);
      });
    }
  }else{//error for no class or no method
    throw new ReferenceError("We're sorry, '" + method + "' is not an available method for " + (plugClass ? functionName(plugClass) : 'this element') + '.');
  }
}else{//error for invalid argument type
  throw new TypeError(`We're sorry, ${type} is not a valid parameter. You must use a string representing the method you wish to invoke.`);
}
return this;

};

window.Foundation = Foundation; $.fn.foundation = foundation;

// Polyfill for requestAnimationFrame (function() {

if (!Date.now || !window.Date.now)
  window.Date.now = Date.now = function() { return new Date().getTime(); };

var vendors = ['webkit', 'moz'];
for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
    var vp = vendors[i];
    window.requestAnimationFrame = window[vp+'RequestAnimationFrame'];
    window.cancelAnimationFrame = (window[vp+'CancelAnimationFrame']
                               || window[vp+'CancelRequestAnimationFrame']);
}
if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent)
  || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
  var lastTime = 0;
  window.requestAnimationFrame = function(callback) {
      var now = Date.now();
      var nextTime = Math.max(lastTime + 16, now);
      return setTimeout(function() { callback(lastTime = nextTime); },
                        nextTime - now);
  };
  window.cancelAnimationFrame = clearTimeout;
}
/**
 * Polyfill for performance.now, required by rAF
 */
if(!window.performance || !window.performance.now){
  window.performance = {
    start: Date.now(),
    now: function(){ return Date.now() - this.start; }
  };
}

})(); if (!Function.prototype.bind) {

Function.prototype.bind = function(oThis) {
  if (typeof this !== 'function') {
    // closest thing possible to the ECMAScript 5
    // internal IsCallable function
    throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
  }

  var aArgs   = Array.prototype.slice.call(arguments, 1),
      fToBind = this,
      fNOP    = function() {},
      fBound  = function() {
        return fToBind.apply(this instanceof fNOP
               ? this
               : oThis,
               aArgs.concat(Array.prototype.slice.call(arguments)));
      };

  if (this.prototype) {
    // native functions don't have a prototype
    fNOP.prototype = this.prototype;
  }
  fBound.prototype = new fNOP();

  return fBound;
};

} // Polyfill to get the name of a function in IE9 function functionName(fn) {

if (Function.prototype.name === undefined) {
  var funcNameRegex = /function\s([^(]{1,})\(/;
  var results = (funcNameRegex).exec((fn).toString());
  return (results && results.length > 1) ? results[1].trim() : "";
}
else if (fn.prototype === undefined) {
  return fn.constructor.name;
}
else {
  return fn.prototype.constructor.name;
}

} function parseValue(str){

if ('true' === str) return true;
else if ('false' === str) return false;
else if (!isNaN(str * 1)) return parseFloat(str);
return str;

} // Convert PascalCase to kebab-case // Thank you: stackoverflow.com/a/8955580 function hyphenate(str) {

return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();

}

}(jQuery);