text: /* -----------------------------------------
     NO CONFLIT - /source/js/cagov/noconflict.js
  ----------------------------------------- */
  
  // Fixes issue with $ not a function
  $ = jQuery.noConflict();
  
  
  /* ========================================================================
   * Bootstrap: alert.js v3.3.5
   * http://getbootstrap.com/javascript/#alerts
   * ========================================================================
   * Copyright 2011-2015 Twitter, Inc.
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
   * ======================================================================== */
  
  
  +function ($) {
    'use strict';
  
    // ALERT CLASS DEFINITION
    // ======================
  
    var dismiss = '[data-dismiss="alert"]'
    var Alert   = function (el) {
      $(el).on('click', dismiss, this.close)
    }
  
    Alert.VERSION = '3.3.5'
  
    Alert.TRANSITION_DURATION = 150
  
    Alert.prototype.close = function (e) {
      var $this    = $(this)
      var selector = $this.attr('data-target')
  
      if (!selector) {
        selector = $this.attr('href')
        selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
      }
  
      var $parent = $(selector)
  
      if (e) e.preventDefault()
  
      if (!$parent.length) {
        $parent = $this.closest('.alert')
      }
  
      $parent.trigger(e = $.Event('close.bs.alert'))
  
      if (e.isDefaultPrevented()) return
  
      $parent.removeClass('in')
  
      function removeElement() {
        // detach from parent, fire event then clean up data
        $parent.detach().trigger('closed.bs.alert').remove()
      }
  
      $.support.transition && $parent.hasClass('fade') ?
        $parent
          .one('bsTransitionEnd', removeElement)
          .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
        removeElement()
    }
  
  
    // ALERT PLUGIN DEFINITION
    // =======================
  
    function Plugin(option) {
      return this.each(function () {
        var $this = $(this)
        var data  = $this.data('bs.alert')
  
        if (!data) $this.data('bs.alert', (data = new Alert(this)))
        if (typeof option == 'string') data[option].call($this)
      })
    }
  
    var old = $.fn.alert
  
    $.fn.alert             = Plugin
    $.fn.alert.Constructor = Alert
  
  
    // ALERT NO CONFLICT
    // =================
  
    $.fn.alert.noConflict = function () {
      $.fn.alert = old
      return this
    }
  
  
    // ALERT DATA-API
    // ==============
  
    $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
  
  }(jQuery);
  
  /* ========================================================================
   * Bootstrap: button.js v3.3.5
   * http://getbootstrap.com/javascript/#buttons
   * ========================================================================
   * Copyright 2011-2015 Twitter, Inc.
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
   * ======================================================================== */
  
  
  +function ($) {
    'use strict';
  
    // BUTTON PUBLIC CLASS DEFINITION
    // ==============================
  
    var Button = function (element, options) {
      this.$element  = $(element)
      this.options   = $.extend({}, Button.DEFAULTS, options)
      this.isLoading = false
    }
  
    Button.VERSION  = '3.3.5'
  
    Button.DEFAULTS = {
      loadingText: 'loading...'
    }
  
    Button.prototype.setState = function (state) {
      var d    = 'disabled'
      var $el  = this.$element
      var val  = $el.is('input') ? 'val' : 'html'
      var data = $el.data()
  
      state += 'Text'
  
      if (data.resetText == null) $el.data('resetText', $el[val]())
  
      // push to event loop to allow forms to submit
      setTimeout($.proxy(function () {
        $el[val](data[state] == null ? this.options[state] : data[state])
  
        if (state == 'loadingText') {
          this.isLoading = true
          $el.addClass(d).attr(d, d)
        } else if (this.isLoading) {
          this.isLoading = false
          $el.removeClass(d).removeAttr(d)
        }
      }, this), 0)
    }
  
    Button.prototype.toggle = function () {
      var changed = true
      var $parent = this.$element.closest('[data-toggle="buttons"]')
  
      if ($parent.length) {
        var $input = this.$element.find('input')
        if ($input.prop('type') == 'radio') {
          if ($input.prop('checked')) changed = false
          $parent.find('.active').removeClass('active')
          this.$element.addClass('active')
        } else if ($input.prop('type') == 'checkbox') {
          if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
          this.$element.toggleClass('active')
        }
        $input.prop('checked', this.$element.hasClass('active'))
        if (changed) $input.trigger('change')
      } else {
        this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
        this.$element.toggleClass('active')
      }
    }
  
  
    // BUTTON PLUGIN DEFINITION
    // ========================
  
    function Plugin(option) {
      return this.each(function () {
        var $this   = $(this)
        var data    = $this.data('bs.button')
        var options = typeof option == 'object' && option
  
        if (!data) $this.data('bs.button', (data = new Button(this, options)))
  
        if (option == 'toggle') data.toggle()
        else if (option) data.setState(option)
      })
    }
  
    var old = $.fn.button
  
    $.fn.button             = Plugin
    $.fn.button.Constructor = Button
  
  
    // BUTTON NO CONFLICT
    // ==================
  
    $.fn.button.noConflict = function () {
      $.fn.button = old
      return this
    }
  
  
    // BUTTON DATA-API
    // ===============
  
    $(document)
      .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
        var $btn = $(e.target)
        if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
        Plugin.call($btn, 'toggle')
        if (!($(e.target).is('input[type="radio"]') || $(e.target).is('input[type="checkbox"]'))) e.preventDefault()
      })
      .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
        $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
      })
  
  }(jQuery);
  
  /* ========================================================================
   * Bootstrap: collapse.js v3.3.5
   * http://getbootstrap.com/javascript/#collapse
   * ========================================================================
   * Copyright 2011-2015 Twitter, Inc.
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
   * ======================================================================== */
  
  
  +function ($) {
    'use strict';
  
    // COLLAPSE PUBLIC CLASS DEFINITION
    // ================================
  
    var Collapse = function (element, options) {
      this.$element      = $(element)
      this.options       = $.extend({}, Collapse.DEFAULTS, options)
      this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
                             '[data-toggle="collapse"][data-target="#' + element.id + '"]')
      this.transitioning = null
  
      if (this.options.parent) {
        this.$parent = this.getParent()
      } else {
        this.addAriaAndCollapsedClass(this.$element, this.$trigger)
      }
  
      if (this.options.toggle) this.toggle()
    }
  
    Collapse.VERSION  = '3.3.5'
  
    Collapse.TRANSITION_DURATION = 350
  
    Collapse.DEFAULTS = {
      toggle: true
    }
  
    Collapse.prototype.dimension = function () {
      var hasWidth = this.$element.hasClass('width')
      return hasWidth ? 'width' : 'height'
    }
  
    Collapse.prototype.show = function () {
      if (this.transitioning || this.$element.hasClass('in')) return
  
      var activesData
      var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
  
      if (actives && actives.length) {
        activesData = actives.data('bs.collapse')
        if (activesData && activesData.transitioning) return
      }
  
      var startEvent = $.Event('show.bs.collapse')
      this.$element.trigger(startEvent)
      if (startEvent.isDefaultPrevented()) return
  
      if (actives && actives.length) {
        Plugin.call(actives, 'hide')
        activesData || actives.data('bs.collapse', null)
      }
  
      var dimension = this.dimension()
  
      this.$element
        .removeClass('collapse')
        .addClass('collapsing')[dimension](0)
        .attr('aria-expanded', true)
  
      this.$trigger
        .removeClass('collapsed')
        .attr('aria-expanded', true)
  
      this.transitioning = 1
  
      var complete = function () {
        this.$element
          .removeClass('collapsing')
          .addClass('collapse in')[dimension]('')
        this.transitioning = 0
        this.$element
          .trigger('shown.bs.collapse')
      }
  
      if (!$.support.transition) return complete.call(this)
  
      var scrollSize = $.camelCase(['scroll', dimension].join('-'))
  
      this.$element
        .one('bsTransitionEnd', $.proxy(complete, this))
        .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
    }
  
    Collapse.prototype.hide = function () {
      if (this.transitioning || !this.$element.hasClass('in')) return
  
      var startEvent = $.Event('hide.bs.collapse')
      this.$element.trigger(startEvent)
      if (startEvent.isDefaultPrevented()) return
  
      var dimension = this.dimension()
  
      this.$element[dimension](this.$element[dimension]())[0].offsetHeight
  
      this.$element
        .addClass('collapsing')
        .removeClass('collapse in')
        .attr('aria-expanded', false)
  
      this.$trigger
        .addClass('collapsed')
        .attr('aria-expanded', false)
  
      this.transitioning = 1
  
      var complete = function () {
        this.transitioning = 0
        this.$element
          .removeClass('collapsing')
          .addClass('collapse')
          .trigger('hidden.bs.collapse')
      }
  
      if (!$.support.transition) return complete.call(this)
  
      this.$element
        [dimension](0)
        .one('bsTransitionEnd', $.proxy(complete, this))
        .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
    }
  
    Collapse.prototype.toggle = function () {
      this[this.$element.hasClass('in') ? 'hide' : 'show']()
    }
  
    Collapse.prototype.getParent = function () {
      return $(this.options.parent)
        .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
        .each($.proxy(function (i, element) {
          var $element = $(element)
          this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
        }, this))
        .end()
    }
  
    Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
      var isOpen = $element.hasClass('in')
  
      $element.attr('aria-expanded', isOpen)
      $trigger
        .toggleClass('collapsed', !isOpen)
        .attr('aria-expanded', isOpen)
    }
  
    function getTargetFromTrigger($trigger) {
      var href
      var target = $trigger.attr('data-target')
        || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
  
      return $(target)
    }
  
  
    // COLLAPSE PLUGIN DEFINITION
    // ==========================
  
    function Plugin(option) {
      return this.each(function () {
        var $this   = $(this)
        var data    = $this.data('bs.collapse')
        var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
  
        if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
        if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
        if (typeof option == 'string') data[option]()
      })
    }
  
    var old = $.fn.collapse
  
    $.fn.collapse             = Plugin
    $.fn.collapse.Constructor = Collapse
  
  
    // COLLAPSE NO CONFLICT
    // ====================
  
    $.fn.collapse.noConflict = function () {
      $.fn.collapse = old
      return this
    }
  
  
    // COLLAPSE DATA-API
    // =================
  
    $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
      var $this   = $(this)
  
      if (!$this.attr('data-target')) e.preventDefault()
  
      var $target = getTargetFromTrigger($this)
      var data    = $target.data('bs.collapse')
      var option  = data ? 'toggle' : $this.data()
  
      Plugin.call($target, option)
    })
  
  }(jQuery);
  
  /* ========================================================================
   * Bootstrap: dropdown.js v3.3.5
   * http://getbootstrap.com/javascript/#dropdowns
   * ========================================================================
   * Copyright 2011-2015 Twitter, Inc.
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
   * ======================================================================== */
  
  
  +function ($) {
    'use strict';
  
    // DROPDOWN CLASS DEFINITION
    // =========================
  
    var backdrop = '.dropdown-backdrop'
    var toggle   = '[data-toggle="dropdown"]'
    var Dropdown = function (element) {
      $(element).on('click.bs.dropdown', this.toggle)
    }
  
    Dropdown.VERSION = '3.3.5'
  
    function getParent($this) {
      var selector = $this.attr('data-target')
  
      if (!selector) {
        selector = $this.attr('href')
        selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
      }
  
      var $parent = selector && $(selector)
  
      return $parent && $parent.length ? $parent : $this.parent()
    }
  
    function clearMenus(e) {
      if (e && e.which === 3) return
      $(backdrop).remove()
      $(toggle).each(function () {
        var $this         = $(this)
        var $parent       = getParent($this)
        var relatedTarget = { relatedTarget: this }
  
        if (!$parent.hasClass('open')) return
  
        if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
  
        $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
  
        if (e.isDefaultPrevented()) return
  
        $this.attr('aria-expanded', 'false')
        $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
      })
    }
  
    Dropdown.prototype.toggle = function (e) {
      var $this = $(this)
  
      if ($this.is('.disabled, :disabled')) return
  
      var $parent  = getParent($this)
      var isActive = $parent.hasClass('open')
  
      clearMenus()
  
      if (!isActive) {
        if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
          // if mobile we use a backdrop because click events don't delegate
          $(document.createElement('div'))
            .addClass('dropdown-backdrop')
            .insertAfter($(this))
            .on('click', clearMenus)
        }
  
        var relatedTarget = { relatedTarget: this }
        $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
  
        if (e.isDefaultPrevented()) return
  
        $this
          .trigger('focus')
          .attr('aria-expanded', 'true')
  
        $parent
          .toggleClass('open')
          .trigger('shown.bs.dropdown', relatedTarget)
      }
  
      return false
    }
  
    Dropdown.prototype.keydown = function (e) {
      if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
  
      var $this = $(this)
  
      e.preventDefault()
      e.stopPropagation()
  
      if ($this.is('.disabled, :disabled')) return
  
      var $parent  = getParent($this)
      var isActive = $parent.hasClass('open')
  
      if (!isActive && e.which != 27 || isActive && e.which == 27) {
        if (e.which == 27) $parent.find(toggle).trigger('focus')
        return $this.trigger('click')
      }
  
      var desc = ' li:not(.disabled):visible a'
      var $items = $parent.find('.dropdown-menu' + desc)
  
      if (!$items.length) return
  
      var index = $items.index(e.target)
  
      if (e.which == 38 && index > 0)                 index--         // up
      if (e.which == 40 && index < $items.length - 1) index++         // down
      if (!~index)                                    index = 0
  
      $items.eq(index).trigger('focus')
    }
  
  
    // DROPDOWN PLUGIN DEFINITION
    // ==========================
  
    function Plugin(option) {
      return this.each(function () {
        var $this = $(this)
        var data  = $this.data('bs.dropdown')
  
        if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
        if (typeof option == 'string') data[option].call($this)
      })
    }
  
    var old = $.fn.dropdown
  
    $.fn.dropdown             = Plugin
    $.fn.dropdown.Constructor = Dropdown
  
  
    // DROPDOWN NO CONFLICT
    // ====================
  
    $.fn.dropdown.noConflict = function () {
      $.fn.dropdown = old
      return this
    }
  
  
    // APPLY TO STANDARD DROPDOWN ELEMENTS
    // ===================================
  
    $(document)
      .on('click.bs.dropdown.data-api', clearMenus)
      .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
      .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
      .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
      .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
  
  }(jQuery);
  
  /* ========================================================================
   * Bootstrap: modal.js v3.3.5
   * http://getbootstrap.com/javascript/#modals
   * ========================================================================
   * Copyright 2011-2015 Twitter, Inc.
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
   * ======================================================================== */
  
  
  +function ($) {
    'use strict';
  
    // MODAL CLASS DEFINITION
    // ======================
  
    var Modal = function (element, options) {
      this.options             = options
      this.$body               = $(document.body)
      this.$element            = $(element)
      this.$dialog             = this.$element.find('.modal-dialog')
      this.$backdrop           = null
      this.isShown             = null
      this.originalBodyPad     = null
      this.scrollbarWidth      = 0
      this.ignoreBackdropClick = false
  
      if (this.options.remote) {
        this.$element
          .find('.modal-content')
          .load(this.options.remote, $.proxy(function () {
            this.$element.trigger('loaded.bs.modal')
          }, this))
      }
    }
  
    Modal.VERSION  = '3.3.5'
  
    Modal.TRANSITION_DURATION = 300
    Modal.BACKDROP_TRANSITION_DURATION = 150
  
    Modal.DEFAULTS = {
      backdrop: true,
      keyboard: true,
      show: true
    }
  
    Modal.prototype.toggle = function (_relatedTarget) {
      return this.isShown ? this.hide() : this.show(_relatedTarget)
    }
  
    Modal.prototype.show = function (_relatedTarget) {
      var that = this
      var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
  
      this.$element.trigger(e)
  
      if (this.isShown || e.isDefaultPrevented()) return
  
      this.isShown = true
  
      this.checkScrollbar()
      this.setScrollbar()
      this.$body.addClass('modal-open')
  	this.$body.removeAttr("style") // beta 5.0 addition
  
      this.escape()
      this.resize()
  
      this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
  
      this.$dialog.on('mousedown.dismiss.bs.modal', function () {
        that.$element.one('mouseup.dismiss.bs.modal', function (e) {
          if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
        })
      })
  
      this.backdrop(function () {
        var transition = $.support.transition && that.$element.hasClass('fade')
  
        if (!that.$element.parent().length) {
          that.$element.appendTo(that.$body) // don't move modals dom position
        }
  
        that.$element
          .show()
          .scrollTop(0)
  
        that.adjustDialog()
  
        if (transition) {
          that.$element[0].offsetWidth // force reflow
        }
  
        that.$element.addClass('in')
  
        that.enforceFocus()
  
        var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
  
        transition ?
          that.$dialog // wait for modal to slide in
            .one('bsTransitionEnd', function () {
              that.$element.trigger('focus').trigger(e)
            })
            .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
          that.$element.trigger('focus').trigger(e)
      })
    }
  
    Modal.prototype.hide = function (e) {
      if (e) e.preventDefault()
  
      e = $.Event('hide.bs.modal')
  
      this.$element.trigger(e)
  
      if (!this.isShown || e.isDefaultPrevented()) return
  
      this.isShown = false
  
      this.escape()
      this.resize()
  
      $(document).off('focusin.bs.modal')
  
      this.$element
        .removeClass('in')
        .off('click.dismiss.bs.modal')
        .off('mouseup.dismiss.bs.modal')
  
      this.$dialog.off('mousedown.dismiss.bs.modal')
  
      $.support.transition && this.$element.hasClass('fade') ?
        this.$element
          .one('bsTransitionEnd', $.proxy(this.hideModal, this))
          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
        this.hideModal()
    }
  
    Modal.prototype.enforceFocus = function () {
      $(document)
        .off('focusin.bs.modal') // guard against infinite focus loop
        .on('focusin.bs.modal', $.proxy(function (e) {
          if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
            this.$element.trigger('focus')
          }
        }, this))
    }
  
    Modal.prototype.escape = function () {
      if (this.isShown && this.options.keyboard) {
        this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
          e.which == 27 && this.hide()
        }, this))
      } else if (!this.isShown) {
        this.$element.off('keydown.dismiss.bs.modal')
      }
    }
  
    Modal.prototype.resize = function () {
      if (this.isShown) {
        $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
      } else {
        $(window).off('resize.bs.modal')
      }
    }
  
    Modal.prototype.hideModal = function () {
      var that = this
      this.$element.hide()
      this.backdrop(function () {
        that.$body.removeClass('modal-open')
        that.resetAdjustments()
        that.resetScrollbar()
        that.$element.trigger('hidden.bs.modal')
      })
    }
  
    Modal.prototype.removeBackdrop = function () {
      this.$backdrop && this.$backdrop.remove()
      this.$backdrop = null
    }
  
    Modal.prototype.backdrop = function (callback) {
      var that = this
      var animate = this.$element.hasClass('fade') ? 'fade' : ''
  
      if (this.isShown && this.options.backdrop) {
        var doAnimate = $.support.transition && animate
  
        this.$backdrop = $(document.createElement('div'))
          .addClass('modal-backdrop ' + animate)
          .appendTo(this.$body)
  
        this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
          if (this.ignoreBackdropClick) {
            this.ignoreBackdropClick = false
            return
          }
          if (e.target !== e.currentTarget) return
          this.options.backdrop == 'static'
            ? this.$element[0].focus()
            : this.hide()
        }, this))
  
        if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
  
        this.$backdrop.addClass('in')
  
        if (!callback) return
  
        doAnimate ?
          this.$backdrop
            .one('bsTransitionEnd', callback)
            .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
          callback()
  
      } else if (!this.isShown && this.$backdrop) {
        this.$backdrop.removeClass('in')
  
        var callbackRemove = function () {
          that.removeBackdrop()
          callback && callback()
        }
        $.support.transition && this.$element.hasClass('fade') ?
          this.$backdrop
            .one('bsTransitionEnd', callbackRemove)
            .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
          callbackRemove()
  
      } else if (callback) {
        callback()
      }
    }
  
    // these following methods are used to handle overflowing modals
  
    Modal.prototype.handleUpdate = function () {
      this.adjustDialog()
    }
  
    Modal.prototype.adjustDialog = function () {
      var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
  
      this.$element.css({
        paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
        paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
      })
    }
  
    Modal.prototype.resetAdjustments = function () {
      this.$element.css({
        paddingLeft: '',
        paddingRight: ''
      })
    }
  
    Modal.prototype.checkScrollbar = function () {
      var fullWindowWidth = window.innerWidth
      if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
        var documentElementRect = document.documentElement.getBoundingClientRect()
        fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
      }
      this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
      this.scrollbarWidth = this.measureScrollbar()
    }
  
    Modal.prototype.setScrollbar = function () {
      var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
      this.originalBodyPad = document.body.style.paddingRight || ''
      if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
    }
  
    Modal.prototype.resetScrollbar = function () {
      this.$body.css('padding-right', this.originalBodyPad)
    }
  
    Modal.prototype.measureScrollbar = function () { // thx walsh
      var scrollDiv = document.createElement('div')
      scrollDiv.className = 'modal-scrollbar-measure'
      this.$body.append(scrollDiv)
      var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
      this.$body[0].removeChild(scrollDiv)
      return scrollbarWidth
    }
  
  
    // MODAL PLUGIN DEFINITION
    // =======================
  
    function Plugin(option, _relatedTarget) {
      return this.each(function () {
        var $this   = $(this)
        var data    = $this.data('bs.modal')
        var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
  
        if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
        if (typeof option == 'string') data[option](_relatedTarget)
        else if (options.show) data.show(_relatedTarget)
      })
    }
  
    var old = $.fn.modal
  
    $.fn.modal             = Plugin
    $.fn.modal.Constructor = Modal
  
  
    // MODAL NO CONFLICT
    // =================
  
    $.fn.modal.noConflict = function () {
      $.fn.modal = old
      return this
    }
  
  
    // MODAL DATA-API
    // ==============
  
    $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
      var $this   = $(this)
      var href    = $this.attr('href')
      var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
      var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
  
      if ($this.is('a')) e.preventDefault()
  
      $target.one('show.bs.modal', function (showEvent) {
        if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
        $target.one('hidden.bs.modal', function () {
          $this.is(':visible') && $this.trigger('focus')
        })
      })
      Plugin.call($target, option, this)
    })
  
  }(jQuery);
  
  /* ========================================================================
   * Bootstrap: tab.js v3.3.5
   * http://getbootstrap.com/javascript/#tabs
   * ========================================================================
   * Copyright 2011-2015 Twitter, Inc.
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
   * ======================================================================== */
  
  
  +function ($) {
    'use strict';
  
    // TAB CLASS DEFINITION
    // ====================
  
    var Tab = function (element) {
      // jscs:disable requireDollarBeforejQueryAssignment
      this.element = $(element)
      // jscs:enable requireDollarBeforejQueryAssignment
    }
  
    Tab.VERSION = '3.3.5'
  
    Tab.TRANSITION_DURATION = 150
  
    Tab.prototype.show = function () {
      var $this    = this.element
      var $ul      = $this.closest('ul:not(.dropdown-menu)')
      var selector = $this.data('target')
  
      if (!selector) {
        selector = $this.attr('href')
        selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
      }
  
      if ($this.parent('li').hasClass('active')) return
  
      var $previous = $ul.find('.active:last a')
      var hideEvent = $.Event('hide.bs.tab', {
        relatedTarget: $this[0]
      })
      var showEvent = $.Event('show.bs.tab', {
        relatedTarget: $previous[0]
      })
  
      $previous.trigger(hideEvent)
      $this.trigger(showEvent)
  
      if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
  
      var $target = $(selector)
  
      this.activate($this.closest('li'), $ul)
      this.activate($target, $target.parent(), function () {
        $previous.trigger({
          type: 'hidden.bs.tab',
          relatedTarget: $this[0]
        })
        $this.trigger({
          type: 'shown.bs.tab',
          relatedTarget: $previous[0]
        })
      })
    }
  
    Tab.prototype.activate = function (element, container, callback) {
      var $active    = container.find('> .active')
      var transition = callback
        && $.support.transition
        && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
  
      function next() {
        $active
          .removeClass('active')
          .find('> .dropdown-menu > .active')
            .removeClass('active')
          .end()
          .find('[data-toggle="tab"]')
            .attr('aria-expanded', false)
  
        element
          .addClass('active')
          .find('[data-toggle="tab"]')
            .attr('aria-expanded', true)
  
        if (transition) {
          element[0].offsetWidth // reflow for transition
          element.addClass('in')
        } else {
          element.removeClass('fade')
        }
  
        if (element.parent('.dropdown-menu').length) {
          element
            .closest('li.dropdown')
              .addClass('active')
            .end()
            .find('[data-toggle="tab"]')
              .attr('aria-expanded', true)
        }
  
        callback && callback()
      }
  
      $active.length && transition ?
        $active
          .one('bsTransitionEnd', next)
          .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
        next()
  
      $active.removeClass('in')
    }
  
  
    // TAB PLUGIN DEFINITION
    // =====================
  
    function Plugin(option) {
      return this.each(function () {
        var $this = $(this)
        var data  = $this.data('bs.tab')
  
        if (!data) $this.data('bs.tab', (data = new Tab(this)))
        if (typeof option == 'string') data[option]()
      })
    }
  
    var old = $.fn.tab
  
    $.fn.tab             = Plugin
    $.fn.tab.Constructor = Tab
  
  
    // TAB NO CONFLICT
    // ===============
  
    $.fn.tab.noConflict = function () {
      $.fn.tab = old
      return this
    }
  
  
    // TAB DATA-API
    // ============
  
    var clickHandler = function (e) {
      e.preventDefault()
      Plugin.call($(this), 'show')
    }
  
    $(document)
      .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
      .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
  
  }(jQuery);
  
  /* ========================================================================
   * Bootstrap: transition.js v3.3.5
   * http://getbootstrap.com/javascript/#transitions
   * ========================================================================
   * Copyright 2011-2015 Twitter, Inc.
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
   * ======================================================================== */
  
  
  +function ($) {
    'use strict';
  
    // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
    // ============================================================
  
    function transitionEnd() {
      var el = document.createElement('bootstrap')
  
      var transEndEventNames = {
        WebkitTransition : 'webkitTransitionEnd',
        MozTransition    : 'transitionend',
        OTransition      : 'oTransitionEnd otransitionend',
        transition       : 'transitionend'
      }
  
      for (var name in transEndEventNames) {
        if (el.style[name] !== undefined) {
          return { end: transEndEventNames[name] }
        }
      }
  
      return false // explicit for ie8 (  ._.)
    }
  
    // http://blog.alexmaccaw.com/css-transitions
    $.fn.emulateTransitionEnd = function (duration) {
      var called = false
      var $el = this
      $(this).one('bsTransitionEnd', function () { called = true })
      var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
      setTimeout(callback, duration)
      return this
    }
  
    $(function () {
      $.support.transition = transitionEnd()
  
      if (!$.support.transition) return
  
      $.event.special.bsTransitionEnd = {
        bindType: $.support.transition.end,
        delegateType: $.support.transition.end,
        handle: function (e) {
          if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
        }
      }
    })
  
  }(jQuery);
  
  /* ========================================================================
   * Bootstrap: tooltip.js v3.3.5
   * http://getbootstrap.com/javascript/#tooltip
   * Inspired by the original jQuery.tipsy by Jason Frame
   * ========================================================================
   * Copyright 2011-2015 Twitter, Inc.
   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
   * ======================================================================== */
  
  
  +function ($) {
    'use strict';
  
    // TOOLTIP PUBLIC CLASS DEFINITION
    // ===============================
  
    var Tooltip = function (element, options) {
      this.type       = null
      this.options    = null
      this.enabled    = null
      this.timeout    = null
      this.hoverState = null
      this.$element   = null
      this.inState    = null
  
      this.init('tooltip', element, options)
    }
  
    Tooltip.VERSION  = '3.3.5'
  
    Tooltip.TRANSITION_DURATION = 150
  
    Tooltip.DEFAULTS = {
      animation: true,
      placement: 'top',
      selector: false,
      template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
      trigger: 'hover focus',
      title: '',
      delay: 0,
      html: false,
      container: false,
      viewport: {
        selector: 'body',
        padding: 0
      }
    }
  
    Tooltip.prototype.init = function (type, element, options) {
      this.enabled   = true
      this.type      = type
      this.$element  = $(element)
      this.options   = this.getOptions(options)
      this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
      this.inState   = { click: false, hover: false, focus: false }
  
      if (this.$element[0] instanceof document.constructor && !this.options.selector) {
        throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
      }
  
      var triggers = this.options.trigger.split(' ')
  
      for (var i = triggers.length; i--;) {
        var trigger = triggers[i]
  
        if (trigger == 'click') {
          this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
        } else if (trigger != 'manual') {
          var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
          var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
  
          this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
          this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
        }
      }
  
      this.options.selector ?
        (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
        this.fixTitle()
    }
  
    Tooltip.prototype.getDefaults = function () {
      return Tooltip.DEFAULTS
    }
  
    Tooltip.prototype.getOptions = function (options) {
      options = $.extend({}, this.getDefaults(), this.$element.data(), options)
  
      if (options.delay && typeof options.delay == 'number') {
        options.delay = {
          show: options.delay,
          hide: options.delay
        }
      }
  
      return options
    }
  
    Tooltip.prototype.getDelegateOptions = function () {
      var options  = {}
      var defaults = this.getDefaults()
  
      this._options && $.each(this._options, function (key, value) {
        if (defaults[key] != value) options[key] = value
      })
  
      return options
    }
  
    Tooltip.prototype.enter = function (obj) {
      var self = obj instanceof this.constructor ?
        obj : $(obj.currentTarget).data('bs.' + this.type)
  
      if (!self) {
        self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
        $(obj.currentTarget).data('bs.' + this.type, self)
      }
  
      if (obj instanceof $.Event) {
        self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
      }
  
      if (self.tip().hasClass('in') || self.hoverState == 'in') {
        self.hoverState = 'in'
        return
      }
  
      clearTimeout(self.timeout)
  
      self.hoverState = 'in'
  
      if (!self.options.delay || !self.options.delay.show) return self.show()
  
      self.timeout = setTimeout(function () {
        if (self.hoverState == 'in') self.show()
      }, self.options.delay.show)
    }
  
    Tooltip.prototype.isInStateTrue = function () {
      for (var key in this.inState) {
        if (this.inState[key]) return true
      }
  
      return false
    }
  
    Tooltip.prototype.leave = function (obj) {
      var self = obj instanceof this.constructor ?
        obj : $(obj.currentTarget).data('bs.' + this.type)
  
      if (!self) {
        self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
        $(obj.currentTarget).data('bs.' + this.type, self)
      }
  
      if (obj instanceof $.Event) {
        self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
      }
  
      if (self.isInStateTrue()) return
  
      clearTimeout(self.timeout)
  
      self.hoverState = 'out'
  
      if (!self.options.delay || !self.options.delay.hide) return self.hide()
  
      self.timeout = setTimeout(function () {
        if (self.hoverState == 'out') self.hide()
      }, self.options.delay.hide)
    }
  
    Tooltip.prototype.show = function () {
      var e = $.Event('show.bs.' + this.type)
  
      if (this.hasContent() && this.enabled) {
        this.$element.trigger(e)
  
        var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
        if (e.isDefaultPrevented() || !inDom) return
        var that = this
  
        var $tip = this.tip()
  
        var tipId = this.getUID(this.type)
  
        this.setContent()
        $tip.attr('id', tipId)
        this.$element.attr('aria-describedby', tipId)
  
        if (this.options.animation) $tip.addClass('fade')
  
        var placement = typeof this.options.placement == 'function' ?
          this.options.placement.call(this, $tip[0], this.$element[0]) :
          this.options.placement
  
        var autoToken = /\s?auto?\s?/i
        var autoPlace = autoToken.test(placement)
        if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
  
        $tip
          .detach()
          .css({ top: 0, left: 0, display: 'block' })
          .addClass(placement)
          .data('bs.' + this.type, this)
  
        this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
        this.$element.trigger('inserted.bs.' + this.type)
  
        var pos          = this.getPosition()
        var actualWidth  = $tip[0].offsetWidth
        var actualHeight = $tip[0].offsetHeight
  
        if (autoPlace) {
          var orgPlacement = placement
          var viewportDim = this.getPosition(this.$viewport)
  
          placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :
                      placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :
                      placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :
                      placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :
                      placement
  
          $tip
            .removeClass(orgPlacement)
            .addClass(placement)
        }
  
        var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
  
        this.applyPlacement(calculatedOffset, placement)
  
        var complete = function () {
          var prevHoverState = that.hoverState
          that.$element.trigger('shown.bs.' + that.type)
          that.hoverState = null
  
          if (prevHoverState == 'out') that.leave(that)
        }
  
        $.support.transition && this.$tip.hasClass('fade') ?
          $tip
            .one('bsTransitionEnd', complete)
            .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
          complete()
      }
    }
  
    Tooltip.prototype.applyPlacement = function (offset, placement) {
      var $tip   = this.tip()
      var width  = $tip[0].offsetWidth
      var height = $tip[0].offsetHeight
  
      // manually read margins because getBoundingClientRect includes difference
      var marginTop = parseInt($tip.css('margin-top'), 10)
      var marginLeft = parseInt($tip.css('margin-left'), 10)
  
      // we must check for NaN for ie 8/9
      if (isNaN(marginTop))  marginTop  = 0
      if (isNaN(marginLeft)) marginLeft = 0
  
      offset.top  += marginTop
      offset.left += marginLeft
  
      // $.fn.offset doesn't round pixel values
      // so we use setOffset directly with our own function B-0
      $.offset.setOffset($tip[0], $.extend({
        using: function (props) {
          $tip.css({
            top: Math.round(props.top),
            left: Math.round(props.left)
          })
        }
      }, offset), 0)
  
      $tip.addClass('in')
  
      // check to see if placing tip in new offset caused the tip to resize itself
      var actualWidth  = $tip[0].offsetWidth
      var actualHeight = $tip[0].offsetHeight
  
      if (placement == 'top' && actualHeight != height) {
        offset.top = offset.top + height - actualHeight
      }
  
      var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
  
      if (delta.left) offset.left += delta.left
      else offset.top += delta.top
  
      var isVertical          = /top|bottom/.test(placement)
      var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
      var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
  
      $tip.offset(offset)
      this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
    }
  
    Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
      this.arrow()
        .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
        .css(isVertical ? 'top' : 'left', '')
    }
  
    Tooltip.prototype.setContent = function () {
      var $tip  = this.tip()
      var title = this.getTitle()
  
      $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
      $tip.removeClass('fade in top bottom left right')
    }
  
    Tooltip.prototype.hide = function (callback) {
      var that = this
      var $tip = $(this.$tip)
      var e    = $.Event('hide.bs.' + this.type)
  
      function complete() {
        if (that.hoverState != 'in') $tip.detach()
        that.$element
          .removeAttr('aria-describedby')
          .trigger('hidden.bs.' + that.type)
        callback && callback()
      }
  
      this.$element.trigger(e)
  
      if (e.isDefaultPrevented()) return
  
      $tip.removeClass('in')
  
      $.support.transition && $tip.hasClass('fade') ?
        $tip
          .one('bsTransitionEnd', complete)
          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
        complete()
  
      this.hoverState = null
  
      return this
    }
  
    Tooltip.prototype.fixTitle = function () {
      var $e = this.$element
      if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
        $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
      }
    }
  
    Tooltip.prototype.hasContent = function () {
      return this.getTitle()
    }
  
    Tooltip.prototype.getPosition = function ($element) {
      $element   = $element || this.$element
  
      var el     = $element[0]
      var isBody = el.tagName == 'BODY'
  
      var elRect    = el.getBoundingClientRect()
      if (elRect.width == null) {
        // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
        elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
      }
      var elOffset  = isBody ? { top: 0, left: 0 } : $element.offset()
      var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
      var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
  
      return $.extend({}, elRect, scroll, outerDims, elOffset)
    }
  
    Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
      return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
             placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
             placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
          /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
  
    }
  
    Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
      var delta = { top: 0, left: 0 }
      if (!this.$viewport) return delta
  
      var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
      var viewportDimensions = this.getPosition(this.$viewport)
  
      if (/right|left/.test(placement)) {
        var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
        var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
        if (topEdgeOffset < viewportDimensions.top) { // top overflow
          delta.top = viewportDimensions.top - topEdgeOffset
        } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
          delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
        }
      } else {
        var leftEdgeOffset  = pos.left - viewportPadding
        var rightEdgeOffset = pos.left + viewportPadding + actualWidth
        if (leftEdgeOffset < viewportDimensions.left) { // left overflow
          delta.left = viewportDimensions.left - leftEdgeOffset
        } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
          delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
        }
      }
  
      return delta
    }
  
    Tooltip.prototype.getTitle = function () {
      var title
      var $e = this.$element
      var o  = this.options
  
      title = $e.attr('data-original-title')
        || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
  
      return title
    }
  
    Tooltip.prototype.getUID = function (prefix) {
      do prefix += ~~(Math.random() * 1000000)
      while (document.getElementById(prefix))
      return prefix
    }
  
    Tooltip.prototype.tip = function () {
      if (!this.$tip) {
        this.$tip = $(this.options.template)
        if (this.$tip.length != 1) {
          throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
        }
      }
      return this.$tip
    }
  
    Tooltip.prototype.arrow = function () {
      return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
    }
  
    Tooltip.prototype.enable = function () {
      this.enabled = true
    }
  
    Tooltip.prototype.disable = function () {
      this.enabled = false
    }
  
    Tooltip.prototype.toggleEnabled = function () {
      this.enabled = !this.enabled
    }
  
    Tooltip.prototype.toggle = function (e) {
      var self = this
      if (e) {
        self = $(e.currentTarget).data('bs.' + this.type)
        if (!self) {
          self = new this.constructor(e.currentTarget, this.getDelegateOptions())
          $(e.currentTarget).data('bs.' + this.type, self)
        }
      }
  
      if (e) {
        self.inState.click = !self.inState.click
        if (self.isInStateTrue()) self.enter(self)
        else self.leave(self)
      } else {
        self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
      }
    }
  
    Tooltip.prototype.destroy = function () {
      var that = this
      clearTimeout(this.timeout)
      this.hide(function () {
        that.$element.off('.' + that.type).removeData('bs.' + that.type)
        if (that.$tip) {
          that.$tip.detach()
        }
        that.$tip = null
        that.$arrow = null
        that.$viewport = null
      })
    }
  
  
    // TOOLTIP PLUGIN DEFINITION
    // =========================
  
    function Plugin(option) {
      return this.each(function () {
        var $this   = $(this)
        var data    = $this.data('bs.tooltip')
        var options = typeof option == 'object' && option
  
        if (!data && /destroy|hide/.test(option)) return
        if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
        if (typeof option == 'string') data[option]()
      })
    }
  
    var old = $.fn.tooltip
  
    $.fn.tooltip             = Plugin
    $.fn.tooltip.Constructor = Tooltip
  
  
    // TOOLTIP NO CONFLICT
    // ===================
  
    $.fn.tooltip.noConflict = function () {
      $.fn.tooltip = old
      return this
    }
  
  }(jQuery);
  
  
    // GENERAL UTILITY FUNCTIONS
    // ===============================
    
    var uniqueId = function(prefix) {
        return (prefix || 'ui-id') + '-' + Math.floor((Math.random()*1000)+1)
    }
  
    
    var removeMultiValAttributes = function (el, attr, val) {
     var describedby = (el.attr( attr ) || "").split( /\s+/ )
        , index = $.inArray(val, describedby)
     if ( index !== -1 ) {
       describedby.splice( index, 1 )
     }
     describedby = $.trim( describedby.join( " " ) )
     if (describedby ) {
       el.attr( attr, describedby )
     } else {
      el.removeAttr( attr )
     }
    }
    // DROPDOWN Extension
    // ===============================
    
    var toggle   = '[data-toggle=dropdown]'
        , $par
        , firstItem
        , focusDelay = 200
        , menus = $(toggle).parent().find('ul').attr('role','menu')
        , lis = menus.find('li').attr('role','presentation')
  
      lis.find('a').attr({'role':'menuitem', 'tabIndex':'-1'})
      $(toggle).attr({ 'aria-haspopup':'true', 'aria-expanded': 'false'})
  
      $(toggle).parent().on('shown.bs.dropdown',function(e){
        $par = $(this)
        var $toggle = $par.find(toggle)
        $toggle.attr('aria-expanded','true')
  
        setTimeout(function(){
              firstItem = $('.dropdown-menu [role=menuitem]:visible', $par)[0]
              try{ firstItem.focus()} catch(ex) {}
        }, focusDelay)
      })
  
      $(toggle).parent().on('hidden.bs.dropdown',function(e){
        $par = $(this)
        var $toggle = $par.find(toggle)
        $toggle.attr('aria-expanded','false')
      })
  
      //Adding Space Key Behaviour, opens on spacebar
      $.fn.dropdown.Constructor.prototype.keydown = function (e) {
        var  $par
          , firstItem
        if (!/(32)/.test(e.keyCode)) return
          $par = $(this).parent()
          $(this).trigger ("click")
          e.preventDefault() && e.stopPropagation()
      }
  
      $(document)
        .on('focusout.dropdown.data-api', '.dropdown-menu', function(e){
          var $this = $(this)
                      , that = this
          setTimeout(function() {
           if(!$.contains(that, document.activeElement)){
            $this.parent().removeClass('open')
            $this.parent().find('[data-toggle=dropdown]').attr('aria-expanded','false')
           }
          }, 150)
         })
        .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu]' , $.fn.dropdown.Constructor.prototype.keydown)
    // Tab Extension
    // ===============================
    
    var $tablist = $('.nav-tabs, .nav-pills')
          , $lis = $tablist.children('li')
          , $tabs = $tablist.find('[data-toggle="tab"], [data-toggle="pill"]')
  
      $tablist.attr('role', 'tablist')
      $lis.attr('role', 'presentation')
      $tabs.attr('role', 'tab')
  
      $tabs.each(function( index ) {
        var tabpanel = $($(this).attr('href'))
          , tab = $(this)
          , tabid = tab.attr('id') || uniqueId('ui-tab')
  
          tab.attr('id', tabid)
  
        if(tab.parent().hasClass('active')){
          tab.attr( { 'tabIndex' : '0', 'aria-selected' : 'true', 'aria-controls': tab.attr('href').substr(1) } )
          tabpanel.attr({ 'role' : 'tabpanel', 'tabIndex' : '0', 'aria-hidden' : 'false', 'aria-labelledby':tabid })
        }else{
          tab.attr( { 'tabIndex' : '-1', 'aria-selected' : 'false', 'aria-controls': tab.attr('href').substr(1) } )
          tabpanel.attr( { 'role' : 'tabpanel', 'tabIndex' : '-1', 'aria-hidden' : 'true', 'aria-labelledby':tabid } )
        }
      })
  
      $.fn.tab.Constructor.prototype.keydown = function (e) {
        var $this = $(this)
        , $items
        , $ul = $this.closest('ul[role=tablist] ')
        , index
        , k = e.which || e.keyCode
  
        $this = $(this)
        if (!/(37|38|39|40)/.test(k)) return
  
        $items = $ul.find('[role=tab]:visible')
        index = $items.index($items.filter(':focus'))
  
        if (k == 38 || k == 37) index--                         // up & left
        if (k == 39 || k == 40) index++                        // down & right
  
  
        if(index < 0) index = $items.length -1
        if(index == $items.length) index = 0
  
        var nextTab = $items.eq(index)
        if(nextTab.attr('role') ==='tab'){
  
          nextTab.tab('show')      //Comment this line for dynamically loaded tabPabels, to save Ajax requests on arrow key navigation
          .focus()
        }
        // nextTab.focus()
  
        e.preventDefault()
        e.stopPropagation()
      }
  
      $(document).on('keydown.tab.data-api','[data-toggle="tab"], [data-toggle="pill"]' , $.fn.tab.Constructor.prototype.keydown)
  
     var tabactivate =    $.fn.tab.Constructor.prototype.activate;
     $.fn.tab.Constructor.prototype.activate = function (element, container, callback) {
        var $active = container.find('> .active')
        $active.find('[data-toggle=tab], [data-toggle=pill]').attr({ 'tabIndex' : '-1','aria-selected' : false })
        $active.filter('.tab-pane').attr({ 'aria-hidden' : true,'tabIndex' : '-1' })
  
        tabactivate.apply(this, arguments)
  
        element.addClass('active')
        element.find('[data-toggle=tab], [data-toggle=pill]').attr({ 'tabIndex' : '0','aria-selected' : true })
        element.filter('.tab-pane').attr({ 'aria-hidden' : false,'tabIndex' : '0' })
     }
  var fakewaffle = ( function ( $, fakewaffle ) {
    'use strict';
  
    var _id= 0;
  
    fakewaffle.responsiveTabs = function ( collapseDisplayed ) {
  
      fakewaffle.currentPosition = 'tabs';
  
      var tabGroups = $( '.nav-tabs.responsive, .nav-pills.responsive' );
      var hidden    = '';
      var visible   = '';
      var activeTab = '';
  
      if ( collapseDisplayed === undefined ) {
        collapseDisplayed = [ 'xs', 'sm' ];
      }
  
      $.each( collapseDisplayed, function () {
        hidden  += ' hidden-' + this;
        visible += ' visible-' + this;
      } );
  
      $.each( tabGroups, function () {
        var $tabGroup   = $( this );
        var tabs        = $tabGroup.find( '[data-toggle="tab"]' );
        var collapseDiv = $( '<div></div>', {
          'class' : 'panel-group responsive' + visible,
          'id'    : 'collapse-' + +'waffle-' + (_id++)
        } );
  
        $.each( tabs, function () {
          var $this          = $( this );
          var oldLinkClass   = $this.attr( 'class' ) === undefined ? '' : $this.attr( 'class' );
          var newLinkClass   = 'accordion-toggle collapsed';
          var oldParentClass = $this.parent().attr( 'class' ) === undefined ? '' : $this.parent().attr( 'class' );
          var newParentClass = 'panel panel-default';
          var newHash        = $this.get( 0 ).hash.replace( '#', 'collapse-' );
  
          if ( oldLinkClass.length > 0 ) {
            newLinkClass += ' ' + oldLinkClass;
          }
  
          if ( oldParentClass.length > 0 ) {
            oldParentClass = oldParentClass.replace( /\bactive\b/g, '' );
            newParentClass += ' ' + oldParentClass;
            newParentClass = newParentClass.replace( /\s{2,}/g, ' ' );
            newParentClass = newParentClass.replace( /^\s+|\s+$/g, '' );
          }
  
          if ( $this.parent().hasClass( 'active' ) ) {
            activeTab = '#' + newHash;
          }
  
          collapseDiv.append(
            $( '<div>' ).attr( 'class', newParentClass ).html(
              $( '<div>' ).attr( 'class', 'panel-heading' ).html(
                $( '<h4>' ).attr( 'class', 'panel-title' ).html(
                  $( '<a>', {
                    'class'       : newLinkClass,
                    'data-toggle' : 'collapse',
                    'data-parent' : '#collapse-' + $tabGroup.attr( 'id' ),
                    'href'        : '#' + newHash,
                    'html'        : $this.html()
                  } )
                )
              )
            ).append(
              $( '<div>', {
                'id'    : newHash,
                'class' : 'panel-collapse collapse'
              } )
            )
          );
        } );
  
        $tabGroup.next().after( collapseDiv );
        $tabGroup.addClass( hidden );
        $( '.tab-content.responsive' ).addClass( hidden );
      } );
  
  
      fakewaffle.checkResize();
      fakewaffle.bindTabToCollapse();
  
      if ( activeTab ) {
        $( activeTab ).collapse( 'show' );
      }
    };
  
    fakewaffle.checkResize = function () {
  
      if ( $( '.panel-group.responsive' ).is( ':visible' ) === true && fakewaffle.currentPosition === 'tabs' ) {
        fakewaffle.tabToPanel();
        fakewaffle.currentPosition = 'panel';
      } else if ( $( '.panel-group.responsive' ).is( ':visible' ) === false && fakewaffle.currentPosition === 'panel' ) {
        fakewaffle.panelToTab();
        fakewaffle.currentPosition = 'tabs';
      }
  
    };
  
    fakewaffle.tabToPanel = function () {
  
      var tabGroups = $( '.nav-tabs.responsive, .nav-pills.responsive' );
  
      $.each( tabGroups, function ( index, tabGroup ) {
  
        // Find the tab
        var tabContents = $( tabGroup ).next( '.tab-content' ).find( '.tab-pane' );
  
        $.each( tabContents, function ( index, tabContent ) {
          // Find the id to move the element to
          var destinationId = $( tabContent ).attr( 'id' ).replace ( /^/, '#collapse-' );
  
          // Convert tab to panel and move to destination
          $( tabContent )
            .removeClass( 'tab-pane' )
            .addClass( 'panel-body' )
            .appendTo( $( destinationId ) );
  
        } );
  
      } );
  
    };
  
    fakewaffle.panelToTab = function () {
  
      var panelGroups = $( '.panel-group.responsive' );
  
      $.each( panelGroups, function ( index, panelGroup ) {
  
        var destinationId = $( panelGroup ).attr( 'id' ).replace( 'collapse-', '#' );
        var destination   = $( destinationId ).next( '.tab-content' )[ 0 ];
  
        // Find the panel contents
        var panelContents = $( panelGroup ).find( '.panel-body' );
  
        // Convert to tab and move to destination
        panelContents
          .removeClass( 'panel-body' )
          .addClass( 'tab-pane' )
          .appendTo( $( destination ) );
  
      } );
  
    };
  
    fakewaffle.bindTabToCollapse = function () {
  
      var tabs     = $( '.nav-tabs.responsive, .nav-pills.responsive' ).find( 'li a' );
      var collapse = $( '.panel-group.responsive' ).find( '.panel-collapse' );
  
      // Toggle the panels when the associated tab is toggled
      tabs.on( 'shown.bs.tab', function ( e ) {
        var $current  = $( e.currentTarget.hash.replace( /#/, '#collapse-' ) );
        $current.collapse( 'show' );
  
        if ( e.relatedTarget ) {
          var $previous = $( e.relatedTarget.hash.replace( /#/, '#collapse-' ) );
          $previous.collapse( 'hide' );
        }
      } );
  
      // Toggle the tab when the associated panel is toggled
      collapse.on( 'shown.bs.collapse', function ( e ) {
  
        // Activate current tabs
        var current = $( e.target ).context.id.replace( /collapse-/g, '#' );
        $( 'a[href="' + current + '"]' ).tab( 'show' );
  
        // Update the content with active
        var panelGroup = $( e.currentTarget ).closest( '.panel-group.responsive' );
        $( panelGroup ).find( '.panel-body' ).removeClass( 'active' );
        $( e.currentTarget ).find( '.panel-body' ).addClass( 'active' );
  
      } );
    };
  
    $( window ).on('resize', function () {
      fakewaffle.checkResize();
    } );
  
    return fakewaffle;
  }( window.jQuery, fakewaffle || { } ) );
  
  /**
   * Owl carousel
   * @version 2.0.0-beta.3
   * @author Bartosz Wojciechowski
   * @license The MIT License (MIT)
   * @todo Lazy Load Icon
   * @todo prevent animationend bubling
   * @todo itemsScaleUp
   * @todo Test Zepto
   * @todo stagePadding calculate wrong active classes
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates a carousel.
     * @class The Owl Carousel.
     * @public
     * @param {HTMLElement|jQuery} element - The element to create the carousel for.
     * @param {Object} [options] - The options
     */
    function Owl(element, options) {
  
      /**
       * Current settings for the carousel.
       * @public
       */
      this.settings = null;
  
      /**
       * Current options set by the caller including defaults.
       * @public
       */
      this.options = $.extend({}, Owl.Defaults, options);
  
      /**
       * Plugin element.
       * @public
       */
      this.$element = $(element);
  
      /**
       * Proxied event handlers.
       * @protected
       */
      this._handlers = {};
  
      /**
       * References to the running plugins of this carousel.
       * @protected
       */
      this._plugins = {};
  
      /**
       * Currently suppressed events to prevent them from beeing retriggered.
       * @protected
       */
      this._supress = {};
  
      /**
       * Absolute current position.
       * @protected
       */
      this._current = null;
  
      /**
       * Animation speed in milliseconds.
       * @protected
       */
      this._speed = null;
  
      /**
       * Coordinates of all items in pixel.
       * @todo The name of this member is missleading.
       * @protected
       */
      this._coordinates = [];
  
      /**
       * Current breakpoint.
       * @todo Real media queries would be nice.
       * @protected
       */
      this._breakpoint = null;
  
      /**
       * Current width of the plugin element.
       */
      this._width = null;
  
      /**
       * All real items.
       * @protected
       */
      this._items = [];
  
      /**
       * All cloned items.
       * @protected
       */
      this._clones = [];
  
      /**
       * Merge values of all items.
       * @todo Maybe this could be part of a plugin.
       * @protected
       */
      this._mergers = [];
  
      /**
       * Widths of all items.
       */
      this._widths = [];
  
      /**
       * Invalidated parts within the update process.
       * @protected
       */
      this._invalidated = {};
  
      /**
       * Ordered list of workers for the update process.
       * @protected
       */
      this._pipe = [];
  
      /**
       * Current state information for the drag operation.
       * @todo #261
       * @protected
       */
      this._drag = {
        time: null,
        target: null,
        pointer: null,
        stage: {
          start: null,
          current: null
        },
        direction: null
      };
  
      /**
       * Current state information and their tags.
       * @type {Object}
       * @protected
       */
      this._states = {
        current: {},
        tags: {
          'initializing': [ 'busy' ],
          'animating': [ 'busy' ],
          'dragging': [ 'interacting' ]
        }
      };
  
      $.each([ 'onResize', 'onThrottledResize' ], $.proxy(function(i, handler) {
        this._handlers[handler] = $.proxy(this[handler], this);
      }, this));
  
      $.each(Owl.Plugins, $.proxy(function(key, plugin) {
        this._plugins[key.charAt(0).toLowerCase() + key.slice(1)]
          = new plugin(this);
      }, this));
  
      $.each(Owl.Workers, $.proxy(function(priority, worker) {
        this._pipe.push({
          'filter': worker.filter,
          'run': $.proxy(worker.run, this)
        });
      }, this));
  
      this.setup();
      this.initialize();
    }
  
    /**
     * Default options for the carousel.
     * @public
     */
    Owl.Defaults = {
      items: 3,
  	autoplay: false,
  	autoplauhoverpause: true,
      loop: true,
      center: false,
      rewind: false,
  
      mouseDrag: true,
      touchDrag: true,
      pullDrag: true,
      freeDrag: false,
  
      margin: 0,
      stagePadding: 0,
  
      merge: false,
      mergeFit: true,
      autoWidth: false,
  
      startPosition: 0,
      rtl: false,
  
      smartSpeed: 250,
      fluidSpeed: false,
      dragEndSpeed: false,
  
      responsive: {},
      responsiveRefreshRate: 200,
      responsiveBaseElement: window,
  
      fallbackEasing: 'swing',
  
      info: false,
  
      nestedItemSelector: false,
      itemElement: 'div',
      stageElement: 'div',
  
      refreshClass: 'owl-refresh',
      loadedClass: 'owl-loaded',
      loadingClass: 'owl-loading',
      rtlClass: 'owl-rtl',
      responsiveClass: 'owl-responsive',
      dragClass: 'owl-drag',
      itemClass: 'owl-item',
      stageClass: 'owl-stage',
      stageOuterClass: 'owl-stage-outer',
      grabClass: 'owl-grab'
    };
  
    /**
     * Enumeration for width.
     * @public
     * @readonly
     * @enum {String}
     */
    Owl.Width = {
      Default: 'default',
      Inner: 'inner',
      Outer: 'outer'
    };
  
    /**
     * Enumeration for types.
     * @public
     * @readonly
     * @enum {String}
     */
    Owl.Type = {
      Event: 'event',
      State: 'state'
    };
  
    /**
     * Contains all registered plugins.
     * @public
     */
    Owl.Plugins = {};
  
    /**
     * List of workers involved in the update process.
     */
    Owl.Workers = [ {
      filter: [ 'width', 'settings' ],
      run: function() {
        this._width = this.$element.width();
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function(cache) {
        cache.current = this._items && this._items[this.relative(this._current)];
      }
    }, {
      filter: [ 'items', 'settings' ],
      run: function() {
        this.$stage.children('.cloned').remove();
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function(cache) {
        var margin = this.settings.margin || '',
          grid = !this.settings.autoWidth,
          rtl = this.settings.rtl,
          css = {
            'width': 'auto',
            'margin-left': rtl ? margin : '',
            'margin-right': rtl ? '' : margin
          };
  
        !grid && this.$stage.children().css(css);
  
        cache.css = css;
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function(cache) {
        var width = (this.width() / this.settings.items).toFixed(3) - this.settings.margin,
          merge = null,
          iterator = this._items.length,
          grid = !this.settings.autoWidth,
          widths = [];
  
        cache.items = {
          merge: false,
          width: width
        };
  
        while (iterator--) {
          merge = this._mergers[iterator];
          merge = this.settings.mergeFit && Math.min(merge, this.settings.items) || merge;
  
          cache.items.merge = merge > 1 || cache.items.merge;
  
          widths[iterator] = !grid ? this._items[iterator].width() : width * merge;
        }
  
        this._widths = widths;
      }
    }, {
      filter: [ 'items', 'settings' ],
      run: function() {
        var clones = [],
          items = this._items,
          settings = this.settings,
          view = Math.max(settings.items * 2, 4),
          size = Math.ceil(items.length / 2) * 2,
          repeat = settings.loop && items.length ? settings.rewind ? view : Math.max(view, size) : 0,
          append = '',
          prepend = '';
  
        repeat /= 2;
  
        while (repeat--) {
          clones.push(this.normalize(clones.length / 2, true));
          append = append + items[clones[clones.length - 1]][0].outerHTML;
          clones.push(this.normalize(items.length - 1 - (clones.length - 1) / 2, true));
          prepend = items[clones[clones.length - 1]][0].outerHTML + prepend;
        }
  
        this._clones = clones;
  
        $(append).addClass('cloned').appendTo(this.$stage);
        $(prepend).addClass('cloned').prependTo(this.$stage);
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function() {
        var rtl = this.settings.rtl ? 1 : -1,
          size = this._clones.length + this._items.length,
          iterator = -1,
          previous = 0,
          current = 0,
          coordinates = [];
  
        while (++iterator < size) {
          previous = coordinates[iterator - 1] || 0;
          current = this._widths[this.relative(iterator)] + this.settings.margin;
          coordinates.push(previous + current * rtl);
        }
  
        this._coordinates = coordinates;
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function() {
        var padding = this.settings.stagePadding,
          coordinates = this._coordinates,
          css = {
            'width': Math.ceil(Math.abs(coordinates[coordinates.length - 1])) + padding * 2,
            'padding-left': padding || '',
            'padding-right': padding || ''
          };
  
        this.$stage.css(css);
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function(cache) {
        var iterator = this._coordinates.length,
          grid = !this.settings.autoWidth,
          items = this.$stage.children();
  
        if (grid && cache.items.merge) {
          while (iterator--) {
            cache.css.width = this._widths[this.relative(iterator)];
            items.eq(iterator).css(cache.css);
          }
        } else if (grid) {
          cache.css.width = cache.items.width;
          items.css(cache.css);
        }
      }
    }, {
      filter: [ 'items' ],
      run: function() {
        this._coordinates.length < 1 && this.$stage.removeAttr('style');
      }
    }, {
      filter: [ 'width', 'items', 'settings' ],
      run: function(cache) {
        cache.current = cache.current ? this.$stage.children().index(cache.current) : 0;
        cache.current = Math.max(this.minimum(), Math.min(this.maximum(), cache.current));
        this.reset(cache.current);
      }
    }, {
      filter: [ 'position' ],
      run: function() {
        this.animate(this.coordinates(this._current));
      }
    }, {
      filter: [ 'width', 'position', 'items', 'settings' ],
      run: function() {
        var rtl = this.settings.rtl ? 1 : -1,
          padding = this.settings.stagePadding * 2,
          begin = this.coordinates(this.current()) + padding,
          end = begin + this.width() * rtl,
          inner, outer, matches = [], i, n;
  
        for (i = 0, n = this._coordinates.length; i < n; i++) {
          inner = this._coordinates[i - 1] || 0;
          outer = Math.abs(this._coordinates[i]) + padding * rtl;
  
          if ((this.op(inner, '<=', begin) && (this.op(inner, '>', end)))
            || (this.op(outer, '<', begin) && this.op(outer, '>', end))) {
            matches.push(i);
          }
        }
  
        this.$stage.children('.active').removeClass('active');
        this.$stage.children(':eq(' + matches.join('), :eq(') + ')').addClass('active');
  
        if (this.settings.center) {
          this.$stage.children('.center').removeClass('center');
          this.$stage.children().eq(this.current()).addClass('center');
        }
      }
    } ];
  
    /**
     * Initializes the carousel.
     * @protected
     */
    Owl.prototype.initialize = function() {
      this.enter('initializing');
      this.trigger('initialize');
  
      this.$element.toggleClass(this.settings.rtlClass, this.settings.rtl);
  
      if (this.settings.autoWidth && !this.is('pre-loading')) {
        var imgs, nestedSelector, width;
        imgs = this.$element.find('img');
        nestedSelector = this.settings.nestedItemSelector ? '.' + this.settings.nestedItemSelector : undefined;
        width = this.$element.children(nestedSelector).width();
  
        if (imgs.length && width <= 0) {
          this.preloadAutoWidthImages(imgs);
        }
      }
  
      this.$element.addClass(this.options.loadingClass);
  
      // create stage
      this.$stage = $('<' + this.settings.stageElement + ' class="' + this.settings.stageClass + '"/>')
        .wrap('<div class="' + this.settings.stageOuterClass + '"/>');
  
      // append stage
      this.$element.append(this.$stage.parent());
  
      // append content
      this.replace(this.$element.children().not(this.$stage.parent()));
  
      // check visibility
      if (this.$element.is(':visible')) {
        // update view
        this.refresh();
      } else {
        // invalidate width
        this.invalidate('width');
      }
  
      this.$element
        .removeClass(this.options.loadingClass)
        .addClass(this.options.loadedClass);
  
      // register event handlers
      this.registerEventHandlers();
  
      this.leave('initializing');
      this.trigger('initialized');
    };
  
    /**
     * Setups the current settings.
     * @todo Remove responsive classes. Why should adaptive designs be brought into IE8?
     * @todo Support for media queries by using `matchMedia` would be nice.
     * @public
     */
    Owl.prototype.setup = function() {
      var viewport = this.viewport(),
        overwrites = this.options.responsive,
        match = -1,
        settings = null;
  
      if (!overwrites) {
        settings = $.extend({}, this.options);
      } else {
        $.each(overwrites, function(breakpoint) {
          if (breakpoint <= viewport && breakpoint > match) {
            match = Number(breakpoint);
          }
        });
  
        settings = $.extend({}, this.options, overwrites[match]);
        delete settings.responsive;
  
        // responsive class
        if (settings.responsiveClass) {
          this.$element.attr('class',
            this.$element.attr('class').replace(new RegExp('(' + this.options.responsiveClass + '-)\\S+\\s', 'g'), '$1' + match)
          );
        }
      }
  
      if (this.settings === null || this._breakpoint !== match) {
        this.trigger('change', { property: { name: 'settings', value: settings } });
        this._breakpoint = match;
        this.settings = settings;
        this.invalidate('settings');
        this.trigger('changed', { property: { name: 'settings', value: this.settings } });
      }
    };
  
    /**
     * Updates option logic if necessery.
     * @protected
     */
    Owl.prototype.optionsLogic = function() {
      if (this.settings.autoWidth) {
        this.settings.stagePadding = false;
        this.settings.merge = false;
      }
    };
  
    /**
     * Prepares an item before add.
     * @todo Rename event parameter `content` to `item`.
     * @protected
     * @returns {jQuery|HTMLElement} - The item container.
     */
    Owl.prototype.prepare = function(item) {
      var event = this.trigger('prepare', { content: item });
  
      if (!event.data) {
        event.data = $('<' + this.settings.itemElement + '/>')
          .addClass(this.options.itemClass).append(item)
      }
  
      this.trigger('prepared', { content: event.data });
  
      return event.data;
    };
  
    /**
     * Updates the view.
     * @public
     */
    Owl.prototype.update = function() {
      var i = 0,
        n = this._pipe.length,
        filter = $.proxy(function(p) { return this[p] }, this._invalidated),
        cache = {};
  
      while (i < n) {
        if (this._invalidated.all || $.grep(this._pipe[i].filter, filter).length > 0) {
          this._pipe[i].run(cache);
        }
        i++;
      }
  
      this._invalidated = {};
  
      !this.is('valid') && this.enter('valid');
    };
  
    /**
     * Gets the width of the view.
     * @public
     * @param {Owl.Width} [dimension=Owl.Width.Default] - The dimension to return.
     * @returns {Number} - The width of the view in pixel.
     */
    Owl.prototype.width = function(dimension) {
      dimension = dimension || Owl.Width.Default;
      switch (dimension) {
        case Owl.Width.Inner:
        case Owl.Width.Outer:
          return this._width;
        default:
          return this._width - this.settings.stagePadding * 2 + this.settings.margin;
      }
    };
  
    /**
     * Refreshes the carousel primarily for adaptive purposes.
     * @public
     */
    Owl.prototype.refresh = function() {
      this.enter('refreshing');
      this.trigger('refresh');
  
      this.setup();
  
      this.optionsLogic();
  
      this.$element.addClass(this.options.refreshClass);
  
      this.update();
  
      this.$element.removeClass(this.options.refreshClass);
  
      this.leave('refreshing');
      this.trigger('refreshed');
    };
  
    /**
     * Checks window `resize` event.
     * @protected
     */
    Owl.prototype.onThrottledResize = function() {
      window.clearTimeout(this.resizeTimer);
      this.resizeTimer = window.setTimeout(this._handlers.onResize, this.settings.responsiveRefreshRate);
    };
  
    /**
     * Checks window `resize` event.
     * @protected
     */
    Owl.prototype.onResize = function() {
      if (!this._items.length) {
        return false;
      }
  
      if (this._width === this.$element.width()) {
        return false;
      }
  
      if (!this.$element.is(':visible')) {
        return false;
      }
  
      this.enter('resizing');
  
      if (this.trigger('resize').isDefaultPrevented()) {
        this.leave('resizing');
        return false;
      }
  
      this.invalidate('width');
  
      this.refresh();
  
      this.leave('resizing');
      this.trigger('resized');
    };
  
    /**
     * Registers event handlers.
     * @todo Check `msPointerEnabled`
     * @todo #261
     * @protected
     */
    Owl.prototype.registerEventHandlers = function() {
      if ($.support.transition) {
        this.$stage.on($.support.transition.end + '.owl.core', $.proxy(this.onTransitionEnd, this));
      }
  
      if (this.settings.responsive !== false) {
        this.on(window, 'resize', this._handlers.onThrottledResize);
      }
  
      if (this.settings.mouseDrag) {
        this.$element.addClass(this.options.dragClass);
        this.$stage.on('mousedown.owl.core', $.proxy(this.onDragStart, this));
        this.$stage.on('dragstart.owl.core selectstart.owl.core', function() { return false });
      }
  
      if (this.settings.touchDrag){
        this.$stage.on('touchstart.owl.core', $.proxy(this.onDragStart, this));
        this.$stage.on('touchcancel.owl.core', $.proxy(this.onDragEnd, this));
      }
    };
  
    /**
     * Handles `touchstart` and `mousedown` events.
     * @todo Horizontal swipe threshold as option
     * @todo #261
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onDragStart = function(event) {
      var stage = null;
  
      if (event.which === 3) {
        return;
      }
  
      if ($.support.transform) {
        stage = this.$stage.css('transform').replace(/.*\(|\)| /g, '').split(',');
        stage = {
          x: stage[stage.length === 16 ? 12 : 4],
          y: stage[stage.length === 16 ? 13 : 5]
        };
      } else {
        stage = this.$stage.position();
        stage = {
          x: this.settings.rtl ?
            stage.left + this.$stage.width() - this.width() + this.settings.margin :
            stage.left,
          y: stage.top
        };
      }
  
      if (this.is('animating')) {
        $.support.transform ? this.animate(stage.x) : this.$stage.stop()
        this.invalidate('position');
      }
  
      this.$element.toggleClass(this.options.grabClass, event.type === 'mousedown');
  
      this.speed(0);
  
      this._drag.time = new Date().getTime();
      this._drag.target = $(event.target);
      this._drag.stage.start = stage;
      this._drag.stage.current = stage;
      this._drag.pointer = this.pointer(event);
  
      $(document).on('mouseup.owl.core touchend.owl.core', $.proxy(this.onDragEnd, this));
  
      $(document).one('mousemove.owl.core touchmove.owl.core', $.proxy(function(event) {
        var delta = this.difference(this._drag.pointer, this.pointer(event));
  
        $(document).on('mousemove.owl.core touchmove.owl.core', $.proxy(this.onDragMove, this));
  
        if (Math.abs(delta.x) < Math.abs(delta.y) && this.is('valid')) {
          return;
        }
  
        event.preventDefault();
  
        this.enter('dragging');
        this.trigger('drag');
      }, this));
    };
  
    /**
     * Handles the `touchmove` and `mousemove` events.
     * @todo #261
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onDragMove = function(event) {
      var minimum = null,
        maximum = null,
        pull = null,
        delta = this.difference(this._drag.pointer, this.pointer(event)),
        stage = this.difference(this._drag.stage.start, delta);
  
      if (!this.is('dragging')) {
        return;
      }
  
      event.preventDefault();
  
      if (this.settings.loop) {
        minimum = this.coordinates(this.minimum());
        maximum = this.coordinates(this.maximum() + 1) - minimum;
        stage.x = (((stage.x - minimum) % maximum + maximum) % maximum) + minimum;
      } else {
        minimum = this.settings.rtl ? this.coordinates(this.maximum()) : this.coordinates(this.minimum());
        maximum = this.settings.rtl ? this.coordinates(this.minimum()) : this.coordinates(this.maximum());
        pull = this.settings.pullDrag ? -1 * delta.x / 5 : 0;
        stage.x = Math.max(Math.min(stage.x, minimum + pull), maximum + pull);
      }
  
      this._drag.stage.current = stage;
  
      this.animate(stage.x);
    };
  
    /**
     * Handles the `touchend` and `mouseup` events.
     * @todo #261
     * @todo Threshold for click event
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onDragEnd = function(event) {
      var delta = this.difference(this._drag.pointer, this.pointer(event)),
        stage = this._drag.stage.current,
        direction = delta.x > 0 ^ this.settings.rtl ? 'left' : 'right';
  
      $(document).off('.owl.core');
  
      this.$element.removeClass(this.options.grabClass);
  
      if (delta.x !== 0 && this.is('dragging') || !this.is('valid')) {
        this.speed(this.settings.dragEndSpeed || this.settings.smartSpeed);
        this.current(this.closest(stage.x, delta.x !== 0 ? direction : this._drag.direction));
        this.invalidate('position');
        this.update();
  
        this._drag.direction = direction;
  
        if (Math.abs(delta.x) > 3 || new Date().getTime() - this._drag.time > 300) {
          this._drag.target.one('click.owl.core', function() { return false; });
        }
      }
  
      if (!this.is('dragging')) {
        return;
      }
  
      this.leave('dragging');
      this.trigger('dragged');
    };
  
    /**
     * Gets absolute position of the closest item for a coordinate.
     * @todo Setting `freeDrag` makes `closest` not reusable. See #165.
     * @protected
     * @param {Number} coordinate - The coordinate in pixel.
     * @param {String} direction - The direction to check for the closest item. Ether `left` or `right`.
     * @return {Number} - The absolute position of the closest item.
     */
    Owl.prototype.closest = function(coordinate, direction) {
      var position = -1,
        pull = 30,
        width = this.width(),
        coordinates = this.coordinates();
  
      if (!this.settings.freeDrag) {
        // check closest item
        $.each(coordinates, $.proxy(function(index, value) {
          if (coordinate > value - pull && coordinate < value + pull) {
            position = index;
          } else if (this.op(coordinate, '<', value)
            && this.op(coordinate, '>', coordinates[index + 1] || value - width)) {
            position = direction === 'left' ? index + 1 : index;
          }
          return position === -1;
        }, this));
      }
  
      if (!this.settings.loop) {
        // non loop boundries
        if (this.op(coordinate, '>', coordinates[this.minimum()])) {
          position = coordinate = this.minimum();
        } else if (this.op(coordinate, '<', coordinates[this.maximum()])) {
          position = coordinate = this.maximum();
        }
      }
  
      return position;
    };
  
    /**
     * Animates the stage.
     * @todo #270
     * @public
     * @param {Number} coordinate - The coordinate in pixels.
     */
    Owl.prototype.animate = function(coordinate) {
      var animate = this.speed() > 0;
  
      this.is('animating') && this.onTransitionEnd();
  
      if (animate) {
        this.enter('animating');
        this.trigger('translate');
      }
  
      if ($.support.transform3d && $.support.transition) {
        this.$stage.css({
          transform: 'translate3d(' + coordinate + 'px,0px,0px)',
          transition: (this.speed() / 1000) + 's'
        });
      } else if (animate) {
        this.$stage.animate({
          left: coordinate + 'px'
        }, this.speed(), this.settings.fallbackEasing, $.proxy(this.onTransitionEnd, this));
      } else {
        this.$stage.css({
          left: coordinate + 'px'
        });
      }
    };
  
    /**
     * Checks whether the carousel is in a specific state or not.
     * @param {String} state - The state to check.
     * @returns {Boolean} - The flag which indicates if the carousel is busy.
     */
    Owl.prototype.is = function(state) {
      return this._states.current[state] && this._states.current[state] > 0;
    };
  
    /**
     * Sets the absolute position of the current item.
     * @public
     * @param {Number} [position] - The new absolute position or nothing to leave it unchanged.
     * @returns {Number} - The absolute position of the current item.
     */
    Owl.prototype.current = function(position) {
      if (position === undefined) {
        return this._current;
      }
  
      if (this._items.length === 0) {
        return undefined;
      }
  
      position = this.normalize(position);
  
      if (this._current !== position) {
        var event = this.trigger('change', { property: { name: 'position', value: position } });
  
        if (event.data !== undefined) {
          position = this.normalize(event.data);
        }
  
        this._current = position;
  
        this.invalidate('position');
  
        this.trigger('changed', { property: { name: 'position', value: this._current } });
      }
  
      return this._current;
    };
  
    /**
     * Invalidates the given part of the update routine.
     * @param {String} [part] - The part to invalidate.
     * @returns {Array.<String>} - The invalidated parts.
     */
    Owl.prototype.invalidate = function(part) {
      if ($.type(part) === 'string') {
        this._invalidated[part] = true;
        this.is('valid') && this.leave('valid');
      }
      return $.map(this._invalidated, function(v, i) { return i });
    };
  
    /**
     * Resets the absolute position of the current item.
     * @public
     * @param {Number} position - The absolute position of the new item.
     */
    Owl.prototype.reset = function(position) {
      position = this.normalize(position);
  
      if (position === undefined) {
        return;
      }
  
      this._speed = 0;
      this._current = position;
  
      this.suppress([ 'translate', 'translated' ]);
  
      this.animate(this.coordinates(position));
  
      this.release([ 'translate', 'translated' ]);
    };
  
    /**
     * Normalizes an absolute or a relative position of an item.
     * @public
     * @param {Number} position - The absolute or relative position to normalize.
     * @param {Boolean} [relative=false] - Whether the given position is relative or not.
     * @returns {Number} - The normalized position.
     */
    Owl.prototype.normalize = function(position, relative) {
      var n = this._items.length,
        m = relative ? 0 : this._clones.length;
  
      if (!$.isNumeric(position) || n < 1) {
        position = undefined;
      } else if (position < 0 || position >= n + m) {
        position = ((position - m / 2) % n + n) % n + m / 2;
      }
  
      return position;
    };
  
    /**
     * Converts an absolute position of an item into a relative one.
     * @public
     * @param {Number} position - The absolute position to convert.
     * @returns {Number} - The converted position.
     */
    Owl.prototype.relative = function(position) {
      position -= this._clones.length / 2;
      return this.normalize(position, true);
    };
  
    /**
     * Gets the maximum position for the current item.
     * @public
     * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
     * @returns {Number}
     */
    Owl.prototype.maximum = function(relative) {
      var settings = this.settings,
        maximum = this._coordinates.length,
        boundary = Math.abs(this._coordinates[maximum - 1]) - this._width,
        i = -1, j;
  
      if (settings.loop) {
        maximum = this._clones.length / 2 + this._items.length - 1;
      } else if (settings.autoWidth || settings.merge) {
        // binary search
        while (maximum - i > 1) {
          Math.abs(this._coordinates[j = maximum + i >> 1]) < boundary
            ? i = j : maximum = j;
        }
      } else if (settings.center) {
        maximum = this._items.length - 1;
      } else {
        maximum = this._items.length - settings.items;
      }
  
      if (relative) {
        maximum -= this._clones.length / 2;
      }
  
      return Math.max(maximum, 0);
    };
  
    /**
     * Gets the minimum position for the current item.
     * @public
     * @param {Boolean} [relative=false] - Whether to return an absolute position or a relative position.
     * @returns {Number}
     */
    Owl.prototype.minimum = function(relative) {
      return relative ? 0 : this._clones.length / 2;
    };
  
    /**
     * Gets an item at the specified relative position.
     * @public
     * @param {Number} [position] - The relative position of the item.
     * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
     */
    Owl.prototype.items = function(position) {
      if (position === undefined) {
        return this._items.slice();
      }
  
      position = this.normalize(position, true);
      return this._items[position];
    };
  
    /**
     * Gets an item at the specified relative position.
     * @public
     * @param {Number} [position] - The relative position of the item.
     * @return {jQuery|Array.<jQuery>} - The item at the given position or all items if no position was given.
     */
    Owl.prototype.mergers = function(position) {
      if (position === undefined) {
        return this._mergers.slice();
      }
  
      position = this.normalize(position, true);
      return this._mergers[position];
    };
  
    /**
     * Gets the absolute positions of clones for an item.
     * @public
     * @param {Number} [position] - The relative position of the item.
     * @returns {Array.<Number>} - The absolute positions of clones for the item or all if no position was given.
     */
    Owl.prototype.clones = function(position) {
      var odd = this._clones.length / 2,
        even = odd + this._items.length,
        map = function(index) { return index % 2 === 0 ? even + index / 2 : odd - (index + 1) / 2 };
  
      if (position === undefined) {
        return $.map(this._clones, function(v, i) { return map(i) });
      }
  
      return $.map(this._clones, function(v, i) { return v === position ? map(i) : null });
    };
  
    /**
     * Sets the current animation speed.
     * @public
     * @param {Number} [speed] - The animation speed in milliseconds or nothing to leave it unchanged.
     * @returns {Number} - The current animation speed in milliseconds.
     */
    Owl.prototype.speed = function(speed) {
      if (speed !== undefined) {
        this._speed = speed;
      }
  
      return this._speed;
    };
  
    /**
     * Gets the coordinate of an item.
     * @todo The name of this method is missleanding.
     * @public
     * @param {Number} position - The absolute position of the item within `minimum()` and `maximum()`.
     * @returns {Number|Array.<Number>} - The coordinate of the item in pixel or all coordinates.
     */
    Owl.prototype.coordinates = function(position) {
      var coordinate = null;
  
      if (position === undefined) {
        return $.map(this._coordinates, $.proxy(function(coordinate, index) {
          return this.coordinates(index);
        }, this));
      }
  
      if (this.settings.center) {
        coordinate = this._coordinates[position];
        coordinate += (this.width() - coordinate + (this._coordinates[position - 1] || 0)) / 2 * (this.settings.rtl ? -1 : 1);
      } else {
        coordinate = this._coordinates[position - 1] || 0;
      }
  
      return coordinate;
    };
  
    /**
     * Calculates the speed for a translation.
     * @protected
     * @param {Number} from - The absolute position of the start item.
     * @param {Number} to - The absolute position of the target item.
     * @param {Number} [factor=undefined] - The time factor in milliseconds.
     * @returns {Number} - The time in milliseconds for the translation.
     */
    Owl.prototype.duration = function(from, to, factor) {
      return Math.min(Math.max(Math.abs(to - from), 1), 6) * Math.abs((factor || this.settings.smartSpeed));
    };
  
    /**
     * Slides to the specified item.
     * @public
     * @param {Number} position - The position of the item.
     * @param {Number} [speed] - The time in milliseconds for the transition.
     */
    Owl.prototype.to = function(position, speed) {
      var current = this.current(),
        revert = null,
        distance = position - this.relative(current),
        direction = (distance > 0) - (distance < 0),
        items = this._items.length,
        minimum = this.minimum(),
        maximum = this.maximum();
  
      if (this.settings.loop) {
        if (!this.settings.rewind && Math.abs(distance) > items / 2) {
          distance += direction * -1 * items;
        }
  
        position = current + distance;
        revert = ((position - minimum) % items + items) % items + minimum;
  
        if (revert !== position && revert - distance <= maximum && revert - distance > 0) {
          current = revert - distance;
          position = revert;
          this.reset(current);
        }
      } else if (this.settings.rewind) {
        maximum += 1;
        position = (position % maximum + maximum) % maximum;
      } else {
        position = Math.max(minimum, Math.min(maximum, position));
      }
  
      this.speed(this.duration(current, position, speed));
      this.current(position);
  
      if (this.$element.is(':visible')) {
        this.update();
      }
    };
  
    /**
     * Slides to the next item.
     * @public
     * @param {Number} [speed] - The time in milliseconds for the transition.
     */
    Owl.prototype.next = function(speed) {
      speed = speed || false;
      this.to(this.relative(this.current()) + 1, speed);
    };
  
    /**
     * Slides to the previous item.
     * @public
     * @param {Number} [speed] - The time in milliseconds for the transition.
     */
    Owl.prototype.prev = function(speed) {
      speed = speed || false;
      this.to(this.relative(this.current()) - 1, speed);
    };
  
    /**
     * Handles the end of an animation.
     * @protected
     * @param {Event} event - The event arguments.
     */
    Owl.prototype.onTransitionEnd = function(event) {
  
      // if css2 animation then event object is undefined
      if (event !== undefined) {
        event.stopPropagation();
  
        // Catch only owl-stage transitionEnd event
        if ((event.target || event.srcElement || event.originalTarget) !== this.$stage.get(0)) {
          return false;
        }
      }
  
      this.leave('animating');
      this.trigger('translated');
    };
  
    /**
     * Gets viewport width.
     * @protected
     * @return {Number} - The width in pixel.
     */
    Owl.prototype.viewport = function() {
      var width;
      if (this.options.responsiveBaseElement !== window) {
        width = $(this.options.responsiveBaseElement).width();
      } else if (window.innerWidth) {
        width = window.innerWidth;
      } else if (document.documentElement && document.documentElement.clientWidth) {
        width = document.documentElement.clientWidth;
      } else {
        throw 'Can not detect viewport width.';
      }
      return width;
    };
  
    /**
     * Replaces the current content.
     * @public
     * @param {HTMLElement|jQuery|String} content - The new content.
     */
    Owl.prototype.replace = function(content) {
      this.$stage.empty();
      this._items = [];
  
      if (content) {
        content = (content instanceof jQuery) ? content : $(content);
      }
  
      if (this.settings.nestedItemSelector) {
        content = content.find('.' + this.settings.nestedItemSelector);
      }
  
      content.filter(function() {
        return this.nodeType === 1;
      }).each($.proxy(function(index, item) {
        item = this.prepare(item);
        this.$stage.append(item);
        this._items.push(item);
        this._mergers.push(item.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
      }, this));
  
      this.reset($.isNumeric(this.settings.startPosition) ? this.settings.startPosition : 0);
  
      this.invalidate('items');
    };
  
    /**
     * Adds an item.
     * @todo Use `item` instead of `content` for the event arguments.
     * @public
     * @param {HTMLElement|jQuery|String} content - The item content to add.
     * @param {Number} [position] - The relative position at which to insert the item otherwise the item will be added to the end.
     */
    Owl.prototype.add = function(content, position) {
      var current = this.relative(this._current);
  
      position = position === undefined ? this._items.length : this.normalize(position, true);
      content = content instanceof jQuery ? content : $(content);
  
      this.trigger('add', { content: content, position: position });
  
      content = this.prepare(content);
  
      if (this._items.length === 0 || position === this._items.length) {
        this._items.length === 0 && this.$stage.append(content);
        this._items.length !== 0 && this._items[position - 1].after(content);
        this._items.push(content);
        this._mergers.push(content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
      } else {
        this._items[position].before(content);
        this._items.splice(position, 0, content);
        this._mergers.splice(position, 0, content.find('[data-merge]').addBack('[data-merge]').attr('data-merge') * 1 || 1);
      }
  
      this._items[current] && this.reset(this._items[current].index());
  
      this.invalidate('items');
  
      this.trigger('added', { content: content, position: position });
    };
  
    /**
     * Removes an item by its position.
     * @todo Use `item` instead of `content` for the event arguments.
     * @public
     * @param {Number} position - The relative position of the item to remove.
     */
    Owl.prototype.remove = function(position) {
      position = this.normalize(position, true);
  
      if (position === undefined) {
        return;
      }
  
      this.trigger('remove', { content: this._items[position], position: position });
  
      this._items[position].remove();
      this._items.splice(position, 1);
      this._mergers.splice(position, 1);
  
      this.invalidate('items');
  
      this.trigger('removed', { content: null, position: position });
    };
  
    /**
     * Preloads images with auto width.
     * @todo Replace by a more generic approach
     * @protected
     */
    Owl.prototype.preloadAutoWidthImages = function(images) {
      images.each($.proxy(function(i, element) {
        this.enter('pre-loading');
        element = $(element);
        $(new Image()).one('load', $.proxy(function(e) {
          element.attr('src', e.target.src);
          element.css('opacity', 1);
          this.leave('pre-loading');
          !this.is('pre-loading') && !this.is('initializing') && this.refresh();
        }, this)).attr('src', element.attr('src') || element.attr('data-src') || element.attr('data-src-retina'));
      }, this));
    };
  
    /**
     * Destroys the carousel.
     * @public
     */
    Owl.prototype.destroy = function() {
  
      this.$element.off('.owl.core');
      this.$stage.off('.owl.core');
      $(document).off('.owl.core');
  
      if (this.settings.responsive !== false) {
        window.clearTimeout(this.resizeTimer);
        this.off(window, 'resize', this._handlers.onThrottledResize);
      }
  
      for (var i in this._plugins) {
        this._plugins[i].destroy();
      }
  
      this.$stage.children('.cloned').remove();
  
      this.$stage.unwrap();
      this.$stage.children().contents().unwrap();
      this.$stage.children().unwrap();
  
      this.$element
        .removeClass(this.options.refreshClass)
        .removeClass(this.options.loadingClass)
        .removeClass(this.options.loadedClass)
        .removeClass(this.options.rtlClass)
        .removeClass(this.options.dragClass)
        .removeClass(this.options.grabClass)
        .attr('class', this.$element.attr('class').replace(new RegExp(this.options.responsiveClass + '-\\S+\\s', 'g'), ''))
        .removeData('owl.carousel');
    };
  
    /**
     * Operators to calculate right-to-left and left-to-right.
     * @protected
     * @param {Number} [a] - The left side operand.
     * @param {String} [o] - The operator.
     * @param {Number} [b] - The right side operand.
     */
    Owl.prototype.op = function(a, o, b) {
      var rtl = this.settings.rtl;
      switch (o) {
        case '<':
          return rtl ? a > b : a < b;
        case '>':
          return rtl ? a < b : a > b;
        case '>=':
          return rtl ? a <= b : a >= b;
        case '<=':
          return rtl ? a >= b : a <= b;
        default:
          break;
      }
    };
  
    /**
     * Attaches to an internal event.
     * @protected
     * @param {HTMLElement} element - The event source.
     * @param {String} event - The event name.
     * @param {Function} listener - The event handler to attach.
     * @param {Boolean} capture - Wether the event should be handled at the capturing phase or not.
     */
    Owl.prototype.on = function(element, event, listener, capture) {
      if (element.addEventListener) {
        element.addEventListener(event, listener, capture);
      } else if (element.attachEvent) {
        element.attachEvent('on' + event, listener);
      }
    };
  
    /**
     * Detaches from an internal event.
     * @protected
     * @param {HTMLElement} element - The event source.
     * @param {String} event - The event name.
     * @param {Function} listener - The attached event handler to detach.
     * @param {Boolean} capture - Wether the attached event handler was registered as a capturing listener or not.
     */
    Owl.prototype.off = function(element, event, listener, capture) {
      if (element.removeEventListener) {
        element.removeEventListener(event, listener, capture);
      } else if (element.detachEvent) {
        element.detachEvent('on' + event, listener);
      }
    };
  
    /**
     * Triggers a public event.
     * @todo Remove `status`, `relatedTarget` should be used instead.
     * @protected
     * @param {String} name - The event name.
     * @param {*} [data=null] - The event data.
     * @param {String} [namespace=carousel] - The event namespace.
     * @param {String} [state] - The state which is associated with the event.
     * @param {Boolean} [enter=false] - Indicates if the call enters the specified state or not.
     * @returns {Event} - The event arguments.
     */
    Owl.prototype.trigger = function(name, data, namespace, state, enter) {
      var status = {
        item: { count: this._items.length, index: this.current() }
      }, handler = $.camelCase(
        $.grep([ 'on', name, namespace ], function(v) { return v })
          .join('-').toLowerCase()
      ), event = $.Event(
        [ name, 'owl', namespace || 'carousel' ].join('.').toLowerCase(),
        $.extend({ relatedTarget: this }, status, data)
      );
  
      if (!this._supress[name]) {
        $.each(this._plugins, function(name, plugin) {
          if (plugin.onTrigger) {
            plugin.onTrigger(event);
          }
        });
  
        this.register({ type: Owl.Type.Event, name: name });
        this.$element.trigger(event);
  
        if (this.settings && typeof this.settings[handler] === 'function') {
          this.settings[handler].call(this, event);
        }
      }
  
      return event;
    };
  
    /**
     * Enters a state.
     * @param name - The state name.
     */
    Owl.prototype.enter = function(name) {
      $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
        if (this._states.current[name] === undefined) {
          this._states.current[name] = 0;
        }
  
        this._states.current[name]++;
      }, this));
    };
  
    /**
     * Leaves a state.
     * @param name - The state name.
     */
    Owl.prototype.leave = function(name) {
      $.each([ name ].concat(this._states.tags[name] || []), $.proxy(function(i, name) {
        this._states.current[name]--;
      }, this));
    };
  
    /**
     * Registers an event or state.
     * @public
     * @param {Object} object - The event or state to register.
     */
    Owl.prototype.register = function(object) {
      if (object.type === Owl.Type.Event) {
        if (!$.event.special[object.name]) {
          $.event.special[object.name] = {};
        }
  
        if (!$.event.special[object.name].owl) {
          var _default = $.event.special[object.name]._default;
          $.event.special[object.name]._default = function(e) {
            if (_default && _default.apply && (!e.namespace || e.namespace.indexOf('owl') === -1)) {
              return _default.apply(this, arguments);
            }
            return e.namespace && e.namespace.indexOf('owl') > -1;
          };
          $.event.special[object.name].owl = true;
        }
      } else if (object.type === Owl.Type.State) {
        if (!this._states.tags[object.name]) {
          this._states.tags[object.name] = object.tags;
        } else {
          this._states.tags[object.name] = this._states.tags[object.name].concat(object.tags);
        }
  
        this._states.tags[object.name] = $.grep(this._states.tags[object.name], $.proxy(function(tag, i) {
          return $.inArray(tag, this._states.tags[object.name]) === i;
        }, this));
      }
    };
  
    /**
     * Suppresses events.
     * @protected
     * @param {Array.<String>} events - The events to suppress.
     */
    Owl.prototype.suppress = function(events) {
      $.each(events, $.proxy(function(index, event) {
        this._supress[event] = true;
      }, this));
    };
  
    /**
     * Releases suppressed events.
     * @protected
     * @param {Array.<String>} events - The events to release.
     */
    Owl.prototype.release = function(events) {
      $.each(events, $.proxy(function(index, event) {
        delete this._supress[event];
      }, this));
    };
  
    /**
     * Gets unified pointer coordinates from event.
     * @todo #261
     * @protected
     * @param {Event} - The `mousedown` or `touchstart` event.
     * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
     */
    Owl.prototype.pointer = function(event) {
      var result = { x: null, y: null };
  
      event = event.originalEvent || event || window.event;
  
      event = event.touches && event.touches.length ?
        event.touches[0] : event.changedTouches && event.changedTouches.length ?
          event.changedTouches[0] : event;
  
      if (event.pageX) {
        result.x = event.pageX;
        result.y = event.pageY;
      } else {
        result.x = event.clientX;
        result.y = event.clientY;
      }
  
      return result;
    };
  
    /**
     * Gets the difference of two vectors.
     * @todo #261
     * @protected
     * @param {Object} - The first vector.
     * @param {Object} - The second vector.
     * @returns {Object} - The difference.
     */
    Owl.prototype.difference = function(first, second) {
      return {
        x: first.x - second.x,
        y: first.y - second.y
      };
    };
  
    /**
     * The jQuery Plugin for the Owl Carousel
     * @todo Navigation plugin `next` and `prev`
     * @public
     */
    $.fn.owlCarousel = function(option) {
      var args = Array.prototype.slice.call(arguments, 1);
  
      return this.each(function() {
        var $this = $(this),
          data = $this.data('owl.carousel');
  
        if (!data) {
          data = new Owl(this, typeof option == 'object' && option);
          $this.data('owl.carousel', data);
  
          $.each([
            'next', 'prev', 'to', 'destroy', 'refresh', 'replace', 'add', 'remove'
          ], function(i, event) {
            data.register({ type: Owl.Type.Event, name: event });
            data.$element.on(event + '.owl.carousel.core', $.proxy(function(e) {
              if (e.namespace && e.relatedTarget !== this) {
                this.suppress([ event ]);
                data[event].apply(this, [].slice.call(arguments, 1));
                this.release([ event ]);
              }
            }, data));
          });
        }
  
        if (typeof option == 'string' && option.charAt(0) !== '_') {
          data[option].apply(data, args);
        }
      });
    };
  
    /**
     * The constructor for the jQuery Plugin
     * @public
     */
    $.fn.owlCarousel.Constructor = Owl;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * AutoRefresh Plugin
   * @version 2.0.0-beta.3
   * @author Artus Kolanowski
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the auto refresh plugin.
     * @class The Auto Refresh Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var AutoRefresh = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * Refresh interval.
       * @protected
       * @type {number}
       */
      this._interval = null;
  
      /**
       * Whether the element is currently visible or not.
       * @protected
       * @type {Boolean}
       */
      this._visible = null;
  
      /**
       * All event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'initialized.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.autoRefresh) {
            this.watch();
          }
        }, this)
      };
  
      // set default options
      this._core.options = $.extend({}, AutoRefresh.Defaults, this._core.options);
  
      // register event handlers
      this._core.$element.on(this._handlers);
    };
  
    /**
     * Default options.
     * @public
     */
    AutoRefresh.Defaults = {
      autoRefresh: true,
      autoRefreshInterval: 500
    };
  
    /**
     * Watches the element.
     */
    AutoRefresh.prototype.watch = function() {
      if (this._interval) {
        return;
      }
  
      this._visible = this._core.$element.is(':visible');
      this._interval = window.setInterval($.proxy(this.refresh, this), this._core.settings.autoRefreshInterval);
    };
  
    /**
     * Refreshes the element.
     */
    AutoRefresh.prototype.refresh = function() {
      if (this._core.$element.is(':visible') === this._visible) {
        return;
      }
  
      this._visible = !this._visible;
  
      this._core.$element.toggleClass('owl-hidden', !this._visible);
  
      this._visible && (this._core.invalidate('width') && this._core.refresh());
    };
  
    /**
     * Destroys the plugin.
     */
    AutoRefresh.prototype.destroy = function() {
      var handler, property;
  
      window.clearInterval(this._interval);
  
      for (handler in this._handlers) {
        this._core.$element.off(handler, this._handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.AutoRefresh = AutoRefresh;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Lazy Plugin
   * @version 2.0.0-beta.3
   * @author Bartosz Wojciechowski
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the lazy plugin.
     * @class The Lazy Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var Lazy = function(carousel) {
  
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * Already loaded items.
       * @protected
       * @type {Array.<jQuery>}
       */
      this._loaded = [];
  
      /**
       * Event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'initialized.owl.carousel change.owl.carousel': $.proxy(function(e) {
          if (!e.namespace) {
            return;
          }
  
          if (!this._core.settings || !this._core.settings.lazyLoad) {
            return;
          }
  
          if ((e.property && e.property.name == 'position') || e.type == 'initialized') {
            var settings = this._core.settings,
              n = (settings.center && Math.ceil(settings.items / 2) || settings.items),
              i = ((settings.center && n * -1) || 0),
              position = ((e.property && e.property.value) || this._core.current()) + i,
              clones = this._core.clones().length,
              load = $.proxy(function(i, v) { this.load(v) }, this);
  
            while (i++ < n) {
              this.load(clones / 2 + this._core.relative(position));
              clones && $.each(this._core.clones(this._core.relative(position)), load);
              position++;
            }
          }
        }, this)
      };
  
      // set the default options
      this._core.options = $.extend({}, Lazy.Defaults, this._core.options);
  
      // register event handler
      this._core.$element.on(this._handlers);
    }
  
    /**
     * Default options.
     * @public
     */
    Lazy.Defaults = {
      lazyLoad: false
    }
  
    /**
     * Loads all resources of an item at the specified position.
     * @param {Number} position - The absolute position of the item.
     * @protected
     */
    Lazy.prototype.load = function(position) {
      var $item = this._core.$stage.children().eq(position),
        $elements = $item && $item.find('.owl-lazy');
  
      if (!$elements || $.inArray($item.get(0), this._loaded) > -1) {
        return;
      }
  
      $elements.each($.proxy(function(index, element) {
        var $element = $(element), image,
          url = (window.devicePixelRatio > 1 && $element.attr('data-src-retina')) || $element.attr('data-src');
  
        this._core.trigger('load', { element: $element, url: url }, 'lazy');
  
        if ($element.is('img')) {
          $element.one('load.owl.lazy', $.proxy(function() {
            $element.css('opacity', 1);
            this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
          }, this)).attr('src', url);
        } else {
          image = new Image();
          image.onload = $.proxy(function() {
            $element.css({
              'background-image': 'url(' + url + ')',
              'opacity': '1'
            });
            this._core.trigger('loaded', { element: $element, url: url }, 'lazy');
          }, this);
          image.src = url;
        }
      }, this));
  
      this._loaded.push($item.get(0));
    }
  
    /**
     * Destroys the plugin.
     * @public
     */
    Lazy.prototype.destroy = function() {
      var handler, property;
  
      for (handler in this.handlers) {
        this._core.$element.off(handler, this.handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.Lazy = Lazy;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * AutoHeight Plugin
   * @version 2.0.0-beta.3
   * @author Bartosz Wojciechowski
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the auto height plugin.
     * @class The Auto Height Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var AutoHeight = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * All event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'initialized.owl.carousel refreshed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.autoHeight) {
            this.update();
          }
        }, this),
        'changed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.autoHeight && e.property.name == 'position'){
            this.update();
          }
        }, this),
        'loaded.owl.lazy': $.proxy(function(e) {
          if (e.namespace && this._core.settings.autoHeight
            && e.element.closest('.' + this._core.settings.itemClass).index() === this._core.current()) {
            this.update();
          }
        }, this)
      };
  
      // set default options
      this._core.options = $.extend({}, AutoHeight.Defaults, this._core.options);
  
      // register event handlers
      this._core.$element.on(this._handlers);
    };
  
    /**
     * Default options.
     * @public
     */
    AutoHeight.Defaults = {
      autoHeight: false,
      autoHeightClass: 'owl-height'
    };
  
    /**
     * Updates the view.
     */
    AutoHeight.prototype.update = function() {
      var start = this._core._current,
        end = start + this._core.settings.items,
        visible = this._core.$stage.children().toArray().slice(start, end);
        heights = [],
        maxheight = 0;
  
      $.each(visible, function(index, item) {
        heights.push($(item).height());
      });
  
      maxheight = Math.max.apply(null, heights);
  
      this._core.$stage.parent()
        .height(maxheight)
        .addClass(this._core.settings.autoHeightClass);
    };
  
    AutoHeight.prototype.destroy = function() {
      var handler, property;
  
      for (handler in this._handlers) {
        this._core.$element.off(handler, this._handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.AutoHeight = AutoHeight;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Video Plugin
   * @version 2.0.0-beta.3
   * @author Bartosz Wojciechowski
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the video plugin.
     * @class The Video Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var Video = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * Cache all video URLs.
       * @protected
       * @type {Object}
       */
      this._videos = {};
  
      /**
       * Current playing item.
       * @protected
       * @type {jQuery}
       */
      this._playing = null;
  
      /**
       * All event handlers.
       * @todo The cloned content removale is too late
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'initialized.owl.carousel': $.proxy(function(e) {
          if (e.namespace) {
            this._core.register({ type: 'state', name: 'playing', tags: [ 'interacting' ] });
          }
        }, this),
        'resize.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.video && this.isInFullScreen()) {
            e.preventDefault();
          }
        }, this),
        'refreshed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.is('resizing')) {
            this._core.$stage.find('.cloned .owl-video-frame').remove();
          }
        }, this),
        'changed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && e.property.name === 'position' && this._playing) {
            this.stop();
          }
        }, this),
        'prepared.owl.carousel': $.proxy(function(e) {
          if (!e.namespace) {
            return;
          }
  
          var $element = $(e.content).find('.owl-video');
  
          if ($element.length) {
            $element.css('display', 'none');
            this.fetch($element, $(e.content));
          }
        }, this)
      };
  
      // set default options
      this._core.options = $.extend({}, Video.Defaults, this._core.options);
  
      // register event handlers
      this._core.$element.on(this._handlers);
  
      this._core.$element.on('click.owl.video', '.owl-video-play-icon', $.proxy(function(e) {
        this.play(e);
      }, this));
    };
  
    /**
     * Default options.
     * @public
     */
    Video.Defaults = {
      video: false,
      videoHeight: false,
      videoWidth: false
    };
  
    /**
     * Gets the video ID and the type (YouTube/Vimeo only).
     * @protected
     * @param {jQuery} target - The target containing the video data.
     * @param {jQuery} item - The item containing the video.
     */
    Video.prototype.fetch = function(target, item) {
      var type = target.attr('data-vimeo-id') ? 'vimeo' : 'youtube',
        id = target.attr('data-vimeo-id') || target.attr('data-youtube-id'),
        width = target.attr('data-width') || this._core.settings.videoWidth,
        height = target.attr('data-height') || this._core.settings.videoHeight,
        url = target.attr('href');
  
      if (url) {
        id = url.match(/(http:|https:|)\/\/(player.|www.)?(vimeo\.com|youtu(be\.com|\.be|be\.googleapis\.com))\/(video\/|embed\/|watch\?v=|v\/)?([A-Za-z0-9._%-]*)(\&\S+)?/);
  
        if (id[3].indexOf('youtu') > -1) {
          type = 'youtube';
        } else if (id[3].indexOf('vimeo') > -1) {
          type = 'vimeo';
        } else {
          throw new Error('Video URL not supported.');
        }
        id = id[6];
      } else {
        throw new Error('Missing video URL.');
      }
  
      this._videos[url] = {
        type: type,
        id: id,
        width: width,
        height: height
      };
  
      item.attr('data-video', url);
  
      this.thumbnail(target, this._videos[url]);
    };
  
    /**
     * Creates video thumbnail.
     * @protected
     * @param {jQuery} target - The target containing the video data.
     * @param {Object} info - The video info object.
     * @see `fetch`
     */
    Video.prototype.thumbnail = function(target, video) {
      var tnLink,
        icon,
        path,
        dimensions = video.width && video.height ? 'style="width:' + video.width + 'px;height:' + video.height + 'px;"' : '',
        customTn = target.find('img'),
        srcType = 'src',
        lazyClass = '',
        settings = this._core.settings,
        create = function(path) {
          icon = '<div class="owl-video-play-icon"></div>';
  
          if (settings.lazyLoad) {
            tnLink = '<div class="owl-video-tn ' + lazyClass + '" ' + srcType + '="' + path + '"></div>';
          } else {
            tnLink = '<div class="owl-video-tn" style="opacity:1;background-image:url(' + path + ')"></div>';
          }
          target.after(tnLink);
          target.after(icon);
        };
  
      // wrap video content into owl-video-wrapper div
      target.wrap('<div class="owl-video-wrapper"' + dimensions + '></div>');
  
      if (this._core.settings.lazyLoad) {
        srcType = 'data-src';
        lazyClass = 'owl-lazy';
      }
  
      // custom thumbnail
      if (customTn.length) {
        create(customTn.attr(srcType));
        customTn.remove();
        return false;
      }
  
      if (video.type === 'youtube') {
        path = "http://img.youtube.com/vi/" + video.id + "/hqdefault.jpg";
        create(path);
      } else if (video.type === 'vimeo') {
        $.ajax({
          type: 'GET',
          url: 'http://vimeo.com/api/v2/video/' + video.id + '.json',
          jsonp: 'callback',
          dataType: 'jsonp',
          success: function(data) {
            path = data[0].thumbnail_large;
            create(path);
          }
        });
      }
    };
  
    /**
     * Stops the current video.
     * @public
     */
    Video.prototype.stop = function() {
      this._core.trigger('stop', null, 'video');
      this._playing.find('.owl-video-frame').remove();
      this._playing.removeClass('owl-video-playing');
      this._playing = null;
      this._core.leave('playing');
      this._core.trigger('stopped', null, 'video');
    };
  
    /**
     * Starts the current video.
     * @public
     * @param {Event} event - The event arguments.
     */
    Video.prototype.play = function(event) {
      var target = $(event.target),
        item = target.closest('.' + this._core.settings.itemClass),
        video = this._videos[item.attr('data-video')],
        width = video.width || '100%',
        height = video.height || this._core.$stage.height(),
        html;
  
      if (this._playing) {
        return;
      }
  
      this._core.enter('playing');
      this._core.trigger('play', null, 'video');
  
      item = this._core.items(this._core.relative(item.index()));
  
      this._core.reset(item.index());
  
      if (video.type === 'youtube') {
        html = '<iframe width="' + width + '" height="' + height + '" src="http://www.youtube.com/embed/' +
          video.id + '?autoplay=1&v=' + video.id + '" frameborder="0" allowfullscreen></iframe>';
      } else if (video.type === 'vimeo') {
        html = '<iframe src="http://player.vimeo.com/video/' + video.id +
          '?autoplay=1" width="' + width + '" height="' + height +
          '" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
      }
  
      $('<div class="owl-video-frame">' + html + '</div>').insertAfter(item.find('.owl-video'));
  
      this._playing = item.addClass('owl-video-playing');
    };
  
    /**
     * Checks whether an video is currently in full screen mode or not.
     * @todo Bad style because looks like a readonly method but changes members.
     * @protected
     * @returns {Boolean}
     */
    Video.prototype.isInFullScreen = function() {
      var element = document.fullscreenElement || document.mozFullScreenElement ||
          document.webkitFullscreenElement;
  
      return element && $(element).parent().hasClass('owl-video-frame');
    };
  
    /**
     * Destroys the plugin.
     */
    Video.prototype.destroy = function() {
      var handler, property;
  
      this._core.$element.off('click.owl.video');
  
      for (handler in this._handlers) {
        this._core.$element.off(handler, this._handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.Video = Video;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Animate Plugin
   * @version 2.0.0-beta.3
   * @author Bartosz Wojciechowski
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the animate plugin.
     * @class The Navigation Plugin
     * @param {Owl} scope - The Owl Carousel
     */
    var Animate = function(scope) {
      this.core = scope;
      this.core.options = $.extend({}, Animate.Defaults, this.core.options);
      this.swapping = true;
      this.previous = undefined;
      this.next = undefined;
  
      this.handlers = {
        'change.owl.carousel': $.proxy(function(e) {
          if (e.namespace && e.property.name == 'position') {
            this.previous = this.core.current();
            this.next = e.property.value;
          }
        }, this),
        'drag.owl.carousel dragged.owl.carousel translated.owl.carousel': $.proxy(function(e) {
          if (e.namespace) {
            this.swapping = e.type == 'translated';
          }
        }, this),
        'translate.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this.swapping && (this.core.options.animateOut || this.core.options.animateIn)) {
            this.swap();
          }
        }, this)
      };
  
      this.core.$element.on(this.handlers);
    };
  
    /**
     * Default options.
     * @public
     */
    Animate.Defaults = {
      animateOut: false,
      animateIn: false
    };
  
    /**
     * Toggles the animation classes whenever an translations starts.
     * @protected
     * @returns {Boolean|undefined}
     */
    Animate.prototype.swap = function() {
  
      if (this.core.settings.items !== 1) {
        return;
      }
  
      if (!$.support.animation || !$.support.transition) {
        return;
      }
  
      this.core.speed(0);
  
      var left,
        clear = $.proxy(this.clear, this),
        previous = this.core.$stage.children().eq(this.previous),
        next = this.core.$stage.children().eq(this.next),
        incoming = this.core.settings.animateIn,
        outgoing = this.core.settings.animateOut;
  
      if (this.core.current() === this.previous) {
        return;
      }
  
      if (outgoing) {
        left = this.core.coordinates(this.previous) - this.core.coordinates(this.next);
        previous.one($.support.animation.end, clear)
          .css( { 'left': left + 'px' } )
          .addClass('animated owl-animated-out')
          .addClass(outgoing);
      }
  
      if (incoming) {
        next.one($.support.animation.end, clear)
          .addClass('animated owl-animated-in')
          .addClass(incoming);
      }
    };
  
    Animate.prototype.clear = function(e) {
      $(e.target).css( { 'left': '' } )
        .removeClass('animated owl-animated-out owl-animated-in')
        .removeClass(this.core.settings.animateIn)
        .removeClass(this.core.settings.animateOut);
      this.core.onTransitionEnd();
    };
  
    /**
     * Destroys the plugin.
     * @public
     */
    Animate.prototype.destroy = function() {
      var handler, property;
  
      for (handler in this.handlers) {
        this.core.$element.off(handler, this.handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.Animate = Animate;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Autoplay Plugin
   * @version 2.0.0-beta.3
   * @author Bartosz Wojciechowski
   * @author Artus Kolanowski
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    /**
     * Creates the autoplay plugin.
     * @class The Autoplay Plugin
     * @param {Owl} scope - The Owl Carousel
     */
    var Autoplay = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * The autoplay interval.
       * @type {Number}
       */
      this._interval = null;
  
      /**
       * Indicates whenever the autoplay is paused.
       * @type {Boolean}
       */
      this._paused = false;
  
      /**
       * All event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'changed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && e.property.name === 'settings') {
            if (this._core.settings.autoplay) {
              this.play();
            } else {
              this.stop();
            }
          }
        }, this),
        'initialized.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.autoplay) {
            this.play();
          }
        }, this),
        'play.owl.autoplay': $.proxy(function(e, t, s) {
          if (e.namespace) {
            this.play(t, s);
          }
        }, this),
        'stop.owl.autoplay': $.proxy(function(e) {
          if (e.namespace) {
            this.stop();
          }
        }, this),
        'mouseover.owl.autoplay': $.proxy(function() {
          if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
            this.pause();
          }
        }, this),
        'mouseleave.owl.autoplay': $.proxy(function() {
          if (this._core.settings.autoplayHoverPause && this._core.is('rotating')) {
            this.play();
          }
        }, this)
      };
  
      // register event handlers
      this._core.$element.on(this._handlers);
  
      // set default options
      this._core.options = $.extend({}, Autoplay.Defaults, this._core.options);
    };
  
    /**
     * Default options.
     * @public
     */
    Autoplay.Defaults = {
      autoplay: true,
      autoplayTimeout: 5000,
      autoplayHoverPause: true,
      autoplaySpeed: false
    };
  
    /**
     * Starts the autoplay.
     * @public
     * @param {Number} [timeout] - The interval before the next animation starts.
     * @param {Number} [speed] - The animation speed for the animations.
     */
    Autoplay.prototype.play = function(timeout, speed) {
      this._paused = false;
  
      if (this._core.is('rotating')) {
        return;
      }
  
      this._core.enter('rotating');
  
      this._interval = window.setInterval($.proxy(function() {
        if (this._paused || this._core.is('busy') || this._core.is('interacting') || document.hidden) {
          return;
        }
        this._core.next(speed || this._core.settings.autoplaySpeed);
      }, this), timeout || this._core.settings.autoplayTimeout);
    };
  
    /**
     * Stops the autoplay.
     * @public
     */
    Autoplay.prototype.stop = function() {
      if (!this._core.is('rotating')) {
        return;
      }
  
      window.clearInterval(this._interval);
      this._core.leave('rotating');
    };
  
    /**
     * Stops the autoplay.
     * @public
     */
    Autoplay.prototype.pause = function() {
      if (!this._core.is('rotating')) {
        return;
      }
  
      this._paused = true;
    };
  
    /**
     * Destroys the plugin.
     */
    Autoplay.prototype.destroy = function() {
      var handler, property;
  
      this.stop();
  
      for (handler in this._handlers) {
        this._core.$element.off(handler, this._handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.autoplay = Autoplay;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Navigation Plugin
   * @version 2.0.0-beta.3
   * @author Artus Kolanowski
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
    'use strict';
  
    /**
     * Creates the navigation plugin.
     * @class The Navigation Plugin
     * @param {Owl} carousel - The Owl Carousel.
     */
    var Navigation = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * Indicates whether the plugin is initialized or not.
       * @protected
       * @type {Boolean}
       */
      this._initialized = false;
  
      /**
       * The current paging indexes.
       * @protected
       * @type {Array}
       */
      this._pages = [];
  
      /**
       * All DOM elements of the user interface.
       * @protected
       * @type {Object}
       */
      this._controls = {};
  
      /**
       * Markup for an indicator.
       * @protected
       * @type {Array.<String>}
       */
      this._templates = [];
  
      /**
       * The carousel element.
       * @type {jQuery}
       */
      this.$element = this._core.$element;
  
      /**
       * Overridden methods of the carousel.
       * @protected
       * @type {Object}
       */
      this._overrides = {
        next: this._core.next,
        prev: this._core.prev,
        to: this._core.to
      };
  
      /**
       * All event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'prepared.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.dotsData) {
            this._templates.push('<div class="' + this._core.settings.dotClass + '">' +
              $(e.content).find('[data-dot]').addBack('[data-dot]').attr('data-dot') + '</div>');
          }
        }, this),
        'added.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.dotsData) {
            this._templates.splice(e.position, 0, this._templates.pop());
          }
        }, this),
        'remove.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.dotsData) {
            this._templates.splice(e.position, 1);
          }
        }, this),
        'changed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && e.property.name == 'position') {
            this.draw();
          }
        }, this),
        'initialized.owl.carousel': $.proxy(function(e) {
          if (e.namespace && !this._initialized) {
            this._core.trigger('initialize', null, 'navigation');
            this.initialize();
            this.update();
            this.draw();
            this._initialized = true;
            this._core.trigger('initialized', null, 'navigation');
          }
        }, this),
        'refreshed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._initialized) {
            this._core.trigger('refresh', null, 'navigation');
            this.update();
            this.draw();
            this._core.trigger('refreshed', null, 'navigation');
          }
        }, this)
      };
  
      // set default options
      this._core.options = $.extend({}, Navigation.Defaults, this._core.options);
  
      // register event handlers
      this.$element.on(this._handlers);
    };
  
    /**
     * Default options.
     * @public
     * @todo Rename `slideBy` to `navBy`
     */
    Navigation.Defaults = {
      nav: false,
      navText: [ 'prev', 'next' ],
      navSpeed: false,
      navElement: 'div',
      navContainer: false,
      navContainerClass: 'owl-nav',
      navClass: [ 'owl-prev', 'owl-next' ],
      slideBy: 1,
      dotClass: 'owl-dot',
      dotsClass: 'owl-dots',
      dots: true,
      dotsEach: false,
      dotsData: false,
      dotsSpeed: false,
      dotsContainer: false
    };
  
    /**
     * Initializes the layout of the plugin and extends the carousel.
     * @protected
     */
    Navigation.prototype.initialize = function() {
      var override,
        settings = this._core.settings;
  
      // create DOM structure for relative navigation
      this._controls.$relative = (settings.navContainer ? $(settings.navContainer)
        : $('<div>').addClass(settings.navContainerClass).appendTo(this.$element)).addClass('disabled');
  
      this._controls.$previous = $('<' + settings.navElement + '>')
        .addClass(settings.navClass[0])
        .html(settings.navText[0])
        .prependTo(this._controls.$relative)
        .on('click', $.proxy(function(e) {
          this.prev(settings.navSpeed);
        }, this));
      this._controls.$next = $('<' + settings.navElement + '>')
        .addClass(settings.navClass[1])
        .html(settings.navText[1])
        .appendTo(this._controls.$relative)
        .on('click', $.proxy(function(e) {
          this.next(settings.navSpeed);
        }, this));
  
      // create DOM structure for absolute navigation
      if (!settings.dotsData) {
        this._templates = [ $('<div>')
          .addClass(settings.dotClass)
          .append($('<span>'))
          .prop('outerHTML') ];
      }
  
      this._controls.$absolute = (settings.dotsContainer ? $(settings.dotsContainer)
        : $('<div>').addClass(settings.dotsClass).appendTo(this.$element)).addClass('disabled');
  
      this._controls.$absolute.on('click', 'div', $.proxy(function(e) {
        var index = $(e.target).parent().is(this._controls.$absolute)
          ? $(e.target).index() : $(e.target).parent().index();
  
        e.preventDefault();
  
        this.to(index, settings.dotsSpeed);
      }, this));
  
      // override public methods of the carousel
      for (override in this._overrides) {
        this._core[override] = $.proxy(this[override], this);
      }
    };
  
    /**
     * Destroys the plugin.
     * @protected
     */
    Navigation.prototype.destroy = function() {
      var handler, control, property, override;
  
      for (handler in this._handlers) {
        this.$element.off(handler, this._handlers[handler]);
      }
      for (control in this._controls) {
        this._controls[control].remove();
      }
      for (override in this.overides) {
        this._core[override] = this._overrides[override];
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    /**
     * Updates the internal state.
     * @protected
     */
    Navigation.prototype.update = function() {
      var i, j, k,
        lower = this._core.clones().length / 2,
        upper = lower + this._core.items().length,
        maximum = this._core.maximum(true),
        settings = this._core.settings,
        size = settings.center || settings.autoWidth || settings.dotsData
          ? 1 : settings.dotsEach || settings.items;
  
      if (settings.slideBy !== 'page') {
        settings.slideBy = Math.min(settings.slideBy, settings.items);
      }
  
      if (settings.dots || settings.slideBy == 'page') {
        this._pages = [];
  
        for (i = lower, j = 0, k = 0; i < upper; i++) {
          if (j >= size || j === 0) {
            this._pages.push({
              start: Math.min(maximum, i - lower),
              end: i - lower + size - 1
            });
            if (Math.min(maximum, i - lower) === maximum) {
              break;
            }
            j = 0, ++k;
          }
          j += this._core.mergers(this._core.relative(i));
        }
      }
    };
  
    /**
     * Draws the user interface.
     * @todo The option `dotsData` wont work.
     * @protected
     */
    Navigation.prototype.draw = function() {
      var difference,
        settings = this._core.settings,
        disabled = this._core.items().length <= settings.items,
        index = this._core.relative(this._core.current()),
        loop = settings.loop || settings.rewind;
  
      this._controls.$relative.toggleClass('disabled', !settings.nav || disabled);
  
      if (settings.nav) {
        this._controls.$previous.toggleClass('disabled', !loop && index <= this._core.minimum(true));
        this._controls.$next.toggleClass('disabled', !loop && index >= this._core.maximum(true));
      }
  
      this._controls.$absolute.toggleClass('disabled', !settings.dots || disabled);
  
      if (settings.dots) {
        difference = this._pages.length - this._controls.$absolute.children().length;
  
        if (settings.dotsData && difference !== 0) {
          this._controls.$absolute.html(this._templates.join(''));
        } else if (difference > 0) {
          this._controls.$absolute.append(new Array(difference + 1).join(this._templates[0]));
        } else if (difference < 0) {
          this._controls.$absolute.children().slice(difference).remove();
        }
  
        this._controls.$absolute.find('.active').removeClass('active');
        this._controls.$absolute.children().eq($.inArray(this.current(), this._pages)).addClass('active');
      }
    };
  
    /**
     * Extends event data.
     * @protected
     * @param {Event} event - The event object which gets thrown.
     */
    Navigation.prototype.onTrigger = function(event) {
      var settings = this._core.settings;
  
      event.page = {
        index: $.inArray(this.current(), this._pages),
        count: this._pages.length,
        size: settings && (settings.center || settings.autoWidth || settings.dotsData
          ? 1 : settings.dotsEach || settings.items)
      };
    };
  
    /**
     * Gets the current page position of the carousel.
     * @protected
     * @returns {Number}
     */
    Navigation.prototype.current = function() {
      var current = this._core.relative(this._core.current());
      return $.grep(this._pages, $.proxy(function(page, index) {
        return page.start <= current && page.end >= current;
      }, this)).pop();
    };
  
    /**
     * Gets the current succesor/predecessor position.
     * @protected
     * @returns {Number}
     */
    Navigation.prototype.getPosition = function(successor) {
      var position, length,
        settings = this._core.settings;
  
      if (settings.slideBy == 'page') {
        position = $.inArray(this.current(), this._pages);
        length = this._pages.length;
        successor ? ++position : --position;
        position = this._pages[((position % length) + length) % length].start;
      } else {
        position = this._core.relative(this._core.current());
        length = this._core.items().length;
        successor ? position += settings.slideBy : position -= settings.slideBy;
      }
  
      return position;
    };
  
    /**
     * Slides to the next item or page.
     * @public
     * @param {Number} [speed=false] - The time in milliseconds for the transition.
     */
    Navigation.prototype.next = function(speed) {
      $.proxy(this._overrides.to, this._core)(this.getPosition(true), speed);
    };
  
    /**
     * Slides to the previous item or page.
     * @public
     * @param {Number} [speed=false] - The time in milliseconds for the transition.
     */
    Navigation.prototype.prev = function(speed) {
      $.proxy(this._overrides.to, this._core)(this.getPosition(false), speed);
    };
  
    /**
     * Slides to the specified item or page.
     * @public
     * @param {Number} position - The position of the item or page.
     * @param {Number} [speed] - The time in milliseconds for the transition.
     * @param {Boolean} [standard=false] - Whether to use the standard behaviour or not.
     */
    Navigation.prototype.to = function(position, speed, standard) {
      var length;
  
      if (!standard) {
        length = this._pages.length;
        $.proxy(this._overrides.to, this._core)(this._pages[((position % length) + length) % length].start, speed);
      } else {
        $.proxy(this._overrides.to, this._core)(position, speed);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.Navigation = Navigation;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Hash Plugin
   * @version 2.0.0-beta.3
   * @author Artus Kolanowski
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
    'use strict';
  
    /**
     * Creates the hash plugin.
     * @class The Hash Plugin
     * @param {Owl} carousel - The Owl Carousel
     */
    var Hash = function(carousel) {
      /**
       * Reference to the core.
       * @protected
       * @type {Owl}
       */
      this._core = carousel;
  
      /**
       * Hash index for the items.
       * @protected
       * @type {Object}
       */
      this._hashes = {};
  
      /**
       * The carousel element.
       * @type {jQuery}
       */
      this.$element = this._core.$element;
  
      /**
       * All event handlers.
       * @protected
       * @type {Object}
       */
      this._handlers = {
        'initialized.owl.carousel': $.proxy(function(e) {
          if (e.namespace && this._core.settings.startPosition === 'URLHash') {
            $(window).trigger('hashchange.owl.navigation');
          }
        }, this),
        'prepared.owl.carousel': $.proxy(function(e) {
          if (e.namespace) {
            var hash = $(e.content).find('[data-hash]').addBack('[data-hash]').attr('data-hash');
  
            if (!hash) {
              return;
            }
  
            this._hashes[hash] = e.content;
          }
        }, this),
        'changed.owl.carousel': $.proxy(function(e) {
          if (e.namespace && e.property.name === 'position') {
            var current = this._core.items(this._core.relative(this._core.current())),
              hash = $.map(this._hashes, function(item, hash) {
                return item === current ? hash : null;
              }).join();
  
            if (!hash || window.location.hash.slice(1) === hash) {
              return;
            }
  
            window.location.hash = hash;
          }
        }, this)
      };
  
      // set default options
      this._core.options = $.extend({}, Hash.Defaults, this._core.options);
  
      // register the event handlers
      this.$element.on(this._handlers);
  
      // register event listener for hash navigation
      $(window).on('hashchange.owl.navigation', $.proxy(function(e) {
        var hash = window.location.hash.substring(1),
          items = this._core.$stage.children(),
          position = this._hashes[hash] && items.index(this._hashes[hash]);
  
        if (position === undefined || position === this._core.current()) {
          return;
        }
  
        this._core.to(this._core.relative(position), false, true);
      }, this));
    };
  
    /**
     * Default options.
     * @public
     */
    Hash.Defaults = {
      URLhashListener: false
    };
  
    /**
     * Destroys the plugin.
     * @public
     */
    Hash.prototype.destroy = function() {
      var handler, property;
  
      $(window).off('hashchange.owl.navigation');
  
      for (handler in this._handlers) {
        this._core.$element.off(handler, this._handlers[handler]);
      }
      for (property in Object.getOwnPropertyNames(this)) {
        typeof this[property] != 'function' && (this[property] = null);
      }
    };
  
    $.fn.owlCarousel.Constructor.Plugins.Hash = Hash;
  
  })(window.Zepto || window.jQuery, window, document);
  
  /**
   * Support Plugin
   *
   * @version 2.0.0-beta.3
   * @author Vivid Planet Software GmbH
   * @author Artus Kolanowski
   * @license The MIT License (MIT)
   */
  ;(function($, window, document, undefined) {
  
    var style = $('<support>').get(0).style,
      prefixes = 'Webkit Moz O ms'.split(' '),
      events = {
        transition: {
          end: {
            WebkitTransition: 'webkitTransitionEnd',
            MozTransition: 'transitionend',
            OTransition: 'oTransitionEnd',
            transition: 'transitionend'
          }
        },
        animation: {
          end: {
            WebkitAnimation: 'webkitAnimationEnd',
            MozAnimation: 'animationend',
            OAnimation: 'oAnimationEnd',
            animation: 'animationend'
          }
        }
      },
      tests = {
        csstransforms: function() {
          return !!test('transform');
        },
        csstransforms3d: function() {
          return !!test('perspective');
        },
        csstransitions: function() {
          return !!test('transition');
        },
        cssanimations: function() {
          return !!test('animation');
        }
      };
  
    function test(property, prefixed) {
      var result = false,
        upper = property.charAt(0).toUpperCase() + property.slice(1);
  
      $.each((property + ' ' + prefixes.join(upper + ' ') + upper).split(' '), function(i, property) {
        if (style[property] !== undefined) {
          result = prefixed ? property : true;
          return false;
        }
      });
  
      return result;
    }
  
    function prefixed(property) {
      return test(property, true);
    }
  
    if (tests.csstransitions()) {
      /* jshint -W053 */
      $.support.transition = new String(prefixed('transition'))
      $.support.transition.end = events.transition.end[ $.support.transition ];
    }
  
    if (tests.cssanimations()) {
      /* jshint -W053 */
      $.support.animation = new String(prefixed('animation'))
      $.support.animation.end = events.animation.end[ $.support.animation ];
    }
  
    if (tests.csstransforms()) {
      /* jshint -W053 */
      $.support.transform = new String(prefixed('transform'));
      $.support.transform3d = tests.csstransforms3d();
    }
  
  })(window.Zepto || window.jQuery, window, document);
  
  /*!
   * fancyBox - jQuery Plugin
   * version: 2.1.5 (Fri, 14 Jun 2013)
   * requires jQuery v1.6 or later
   *
   * Examples at http://fancyapps.com/fancybox/
   * License: www.fancyapps.com/fancybox/#license
   *
   * Copyright 2012 Janis Skarnelis - janis@fancyapps.com
   *
   */
  
  ;(function (window, document, $, undefined) {
  	"use strict";
  
  	var H = $("html"),
  		W = $(window),
  		D = $(document),
  		F = $.fancybox = function () {
  			F.open.apply( this, arguments );
  		},
  		IE =  navigator.userAgent.match(/msie/i),
  		didUpdate	= null,
  		isTouch		= document.createTouch !== undefined,
  
  		isQuery	= function(obj) {
  			return obj && obj.hasOwnProperty && obj instanceof $;
  		},
  		isString = function(str) {
  			return str && $.type(str) === "string";
  		},
  		isPercentage = function(str) {
  			return isString(str) && str.indexOf('%') > 0;
  		},
  		isScrollable = function(el) {
  			return (el && !(el.style.overflow && el.style.overflow === 'hidden') && ((el.clientWidth && el.scrollWidth > el.clientWidth) || (el.clientHeight && el.scrollHeight > el.clientHeight)));
  		},
  		getScalar = function(orig, dim) {
  			var value = parseInt(orig, 10) || 0;
  
  			if (dim && isPercentage(orig)) {
  				value = F.getViewport()[ dim ] / 100 * value;
  			}
  
  			return Math.ceil(value);
  		},
  		getValue = function(value, dim) {
  			return getScalar(value, dim) + 'px';
  		};
  
  	$.extend(F, {
  		// The current version of fancyBox
  		version: '2.1.5',
  
  		defaults: {
  			padding : 15,
  			margin  : 20,
  
  			width     : 800,
  			height    : 600,
  			minWidth  : 100,
  			minHeight : 100,
  			maxWidth  : 9999,
  			maxHeight : 9999,
  			pixelRatio: 1, // Set to 2 for retina display support
  
  			autoSize   : true,
  			autoHeight : false,
  			autoWidth  : false,
  
  			autoResize  : true,
  			autoCenter  : !isTouch,
  			fitToView   : true,
  			aspectRatio : false,
  			topRatio    : 0.5,
  			leftRatio   : 0.5,
  
  			scrolling : 'auto', // 'auto', 'yes' or 'no'
  			wrapCSS   : '',
  
  			arrows     : true,
  			closeBtn   : true,
  			closeClick : false,
  			nextClick  : false,
  			mouseWheel : true,
  			autoPlay   : false,
  			playSpeed  : 3000,
  			preload    : 3,
  			modal      : false,
  			loop       : true,
  
  			ajax  : {
  				dataType : 'html',
  				headers  : { 'X-fancyBox': true }
  			},
  			iframe : {
  				scrolling : 'auto',
  				preload   : true
  			},
  			swf : {
  				wmode: 'transparent',
  				allowfullscreen   : 'true',
  				allowscriptaccess : 'always'
  			},
  
  			keys  : {
  				next : {
  					13 : 'left', // enter
  					34 : 'up',   // page down
  					39 : 'left', // right arrow
  					40 : 'up'    // down arrow
  				},
  				prev : {
  					8  : 'right',  // backspace
  					33 : 'down',   // page up
  					37 : 'right',  // left arrow
  					38 : 'down'    // up arrow
  				},
  				close  : [27], // escape key
  				play   : [32], // space - start/stop slideshow
  				toggle : [70]  // letter "f" - toggle fullscreen
  			},
  
  			direction : {
  				next : 'left',
  				prev : 'right'
  			},
  
  			scrollOutside  : true,
  
  			// Override some properties
  			index   : 0,
  			type    : null,
  			href    : null,
  			content : null,
  			title   : null,
  
  			// HTML templates
  			tpl: {
  				wrap     : '<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>',
  				image    : '<img class="fancybox-image" src="{href}" alt="" />',
  				iframe   : '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen' + (IE ? ' allowtransparency="true"' : '') + '></iframe>',
  				error    : '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',
  				closeBtn : '<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>',
  				next     : '<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>',
  				prev     : '<a title="Previous" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>',
  				loading  : '<div id="fancybox-loading"><div></div></div>'
  			},
  
  			// Properties for each animation type
  			// Opening fancyBox
  			openEffect  : 'fade', // 'elastic', 'fade' or 'none'
  			openSpeed   : 250,
  			openEasing  : 'swing',
  			openOpacity : true,
  			openMethod  : 'zoomIn',
  
  			// Closing fancyBox
  			closeEffect  : 'fade', // 'elastic', 'fade' or 'none'
  			closeSpeed   : 250,
  			closeEasing  : 'swing',
  			closeOpacity : true,
  			closeMethod  : 'zoomOut',
  
  			// Changing next gallery item
  			nextEffect : 'elastic', // 'elastic', 'fade' or 'none'
  			nextSpeed  : 250,
  			nextEasing : 'swing',
  			nextMethod : 'changeIn',
  
  			// Changing previous gallery item
  			prevEffect : 'elastic', // 'elastic', 'fade' or 'none'
  			prevSpeed  : 250,
  			prevEasing : 'swing',
  			prevMethod : 'changeOut',
  
  			// Enable default helpers
  			helpers : {
  				overlay : true,
  				title   : true
  			},
  
  			// Callbacks
  			onCancel     : $.noop, // If canceling
  			beforeLoad   : $.noop, // Before loading
  			afterLoad    : $.noop, // After loading
  			beforeShow   : $.noop, // Before changing in current item
  			afterShow    : $.noop, // After opening
  			beforeChange : $.noop, // Before changing gallery item
  			beforeClose  : $.noop, // Before closing
  			afterClose   : $.noop  // After closing
  		},
  
  		//Current state
  		group    : {}, // Selected group
  		opts     : {}, // Group options
  		previous : null,  // Previous element
  		coming   : null,  // Element being loaded
  		current  : null,  // Currently loaded element
  		isActive : false, // Is activated
  		isOpen   : false, // Is currently open
  		isOpened : false, // Have been fully opened at least once
  
  		wrap  : null,
  		skin  : null,
  		outer : null,
  		inner : null,
  
  		player : {
  			timer    : null,
  			isActive : false
  		},
  
  		// Loaders
  		ajaxLoad   : null,
  		imgPreload : null,
  
  		// Some collections
  		transitions : {},
  		helpers     : {},
  
  		/*
  		 *	Static methods
  		 */
  
  		open: function (group, opts) {
  			if (!group) {
  				return;
  			}
  
  			if (!$.isPlainObject(opts)) {
  				opts = {};
  			}
  
  			// Close if already active
  			if (false === F.close(true)) {
  				return;
  			}
  
  			// Normalize group
  			if (!$.isArray(group)) {
  				group = isQuery(group) ? $(group).get() : [group];
  			}
  
  			// Recheck if the type of each element is `object` and set content type (image, ajax, etc)
  			$.each(group, function(i, element) {
  				var obj = {},
  					href,
  					title,
  					content,
  					type,
  					rez,
  					hrefParts,
  					selector;
  
  				if ($.type(element) === "object") {
  					// Check if is DOM element
  					if (element.nodeType) {
  						element = $(element);
  					}
  
  					if (isQuery(element)) {
  						obj = {
  							href    : element.data('fancybox-href') || element.attr('href'),
  							title   : $('<div/>').text( element.data('fancybox-title') || element.attr('title') || '' ).html(),
  							isDom   : true,
  							element : element
  						};
  
  						if ($.metadata) {
  							$.extend(true, obj, element.metadata());
  						}
  
  					} else {
  						obj = element;
  					}
  				}
  
  				href  = opts.href  || obj.href || (isString(element) ? element : null);
  				title = opts.title !== undefined ? opts.title : obj.title || '';
  
  				content = opts.content || obj.content;
  				type    = content ? 'html' : (opts.type  || obj.type);
  
  				if (!type && obj.isDom) {
  					type = element.data('fancybox-type');
  
  					if (!type) {
  						rez  = element.prop('class').match(/fancybox\.(\w+)/);
  						type = rez ? rez[1] : null;
  					}
  				}
  
  				if (isString(href)) {
  					// Try to guess the content type
  					if (!type) {
  						if (F.isImage(href)) {
  							type = 'image';
  
  						} else if (F.isSWF(href)) {
  							type = 'swf';
  
  						} else if (href.charAt(0) === '#') {
  							type = 'inline';
  
  						} else if (isString(element)) {
  							type    = 'html';
  							content = element;
  						}
  					}
  
  					// Split url into two pieces with source url and content selector, e.g,
  					// "/mypage.html #my_id" will load "/mypage.html" and display element having id "my_id"
  					if (type === 'ajax') {
  						hrefParts = href.split(/\s+/, 2);
  						href      = hrefParts.shift();
  						selector  = hrefParts.shift();
  					}
  				}
  
  				if (!content) {
  					if (type === 'inline') {
  						if (href) {
  							content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7
  
  						} else if (obj.isDom) {
  							content = element;
  						}
  
  					} else if (type === 'html') {
  						content = href;
  
  					} else if (!type && !href && obj.isDom) {
  						type    = 'inline';
  						content = element;
  					}
  				}
  
  				$.extend(obj, {
  					href     : href,
  					type     : type,
  					content  : content,
  					title    : title,
  					selector : selector
  				});
  
  				group[ i ] = obj;
  			});
  
  			// Extend the defaults
  			F.opts = $.extend(true, {}, F.defaults, opts);
  
  			// All options are merged recursive except keys
  			if (opts.keys !== undefined) {
  				F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false;
  			}
  
  			F.group = group;
  
  			return F._start(F.opts.index);
  		},
  
  		// Cancel image loading or abort ajax request
  		cancel: function () {
  			var coming = F.coming;
  
  			if (coming && false === F.trigger('onCancel')) {
  				return;
  			}
  
  			F.hideLoading();
  
  			if (!coming) {
  				return;
  			}
  
  			if (F.ajaxLoad) {
  				F.ajaxLoad.abort();
  			}
  
  			F.ajaxLoad = null;
  
  			if (F.imgPreload) {
  				F.imgPreload.onload = F.imgPreload.onerror = null;
  			}
  
  			if (coming.wrap) {
  				coming.wrap.stop(true, true).trigger('onReset').remove();
  			}
  
  			F.coming = null;
  
  			// If the first item has been canceled, then clear everything
  			if (!F.current) {
  				F._afterZoomOut( coming );
  			}
  		},
  
  		// Start closing animation if is open; remove immediately if opening/closing
  		close: function (event) {
  			F.cancel();
  
  			if (false === F.trigger('beforeClose')) {
  				return;
  			}
  
  			F.unbindEvents();
  
  			if (!F.isActive) {
  				return;
  			}
  
  			if (!F.isOpen || event === true) {
  				$('.fancybox-wrap').stop(true).trigger('onReset').remove();
  
  				F._afterZoomOut();
  
  			} else {
  				F.isOpen = F.isOpened = false;
  				F.isClosing = true;
  
  				$('.fancybox-item, .fancybox-nav').remove();
  
  				F.wrap.stop(true, true).removeClass('fancybox-opened');
  
  				F.transitions[ F.current.closeMethod ]();
  			}
  		},
  
  		// Manage slideshow:
  		//   $.fancybox.play(); - toggle slideshow
  		//   $.fancybox.play( true ); - start
  		//   $.fancybox.play( false ); - stop
  		play: function ( action ) {
  			var clear = function () {
  					clearTimeout(F.player.timer);
  				},
  				set = function () {
  					clear();
  
  					if (F.current && F.player.isActive) {
  						F.player.timer = setTimeout(F.next, F.current.playSpeed);
  					}
  				},
  				stop = function () {
  					clear();
  
  					D.unbind('.player');
  
  					F.player.isActive = false;
  
  					F.trigger('onPlayEnd');
  				},
  				start = function () {
  					if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) {
  						F.player.isActive = true;
  
  						D.bind({
  							'onCancel.player beforeClose.player' : stop,
  							'onUpdate.player'   : set,
  							'beforeLoad.player' : clear
  						});
  
  						set();
  
  						F.trigger('onPlayStart');
  					}
  				};
  
  			if (action === true || (!F.player.isActive && action !== false)) {
  				start();
  			} else {
  				stop();
  			}
  		},
  
  		// Navigate to next gallery item
  		next: function ( direction ) {
  			var current = F.current;
  
  			if (current) {
  				if (!isString(direction)) {
  					direction = current.direction.next;
  				}
  
  				F.jumpto(current.index + 1, direction, 'next');
  			}
  		},
  
  		// Navigate to previous gallery item
  		prev: function ( direction ) {
  			var current = F.current;
  
  			if (current) {
  				if (!isString(direction)) {
  					direction = current.direction.prev;
  				}
  
  				F.jumpto(current.index - 1, direction, 'prev');
  			}
  		},
  
  		// Navigate to gallery item by index
  		jumpto: function ( index, direction, router ) {
  			var current = F.current;
  
  			if (!current) {
  				return;
  			}
  
  			index = getScalar(index);
  
  			F.direction = direction || current.direction[ (index >= current.index ? 'next' : 'prev') ];
  			F.router    = router || 'jumpto';
  
  			if (current.loop) {
  				if (index < 0) {
  					index = current.group.length + (index % current.group.length);
  				}
  
  				index = index % current.group.length;
  			}
  
  			if (current.group[ index ] !== undefined) {
  				F.cancel();
  
  				F._start(index);
  			}
  		},
  
  		// Center inside viewport and toggle position type to fixed or absolute if needed
  		reposition: function (e, onlyAbsolute) {
  			var current = F.current,
  				wrap    = current ? current.wrap : null,
  				pos;
  
  			if (wrap) {
  				pos = F._getPosition(onlyAbsolute);
  
  				if (e && e.type === 'scroll') {
  					delete pos.position;
  
  					wrap.stop(true, true).animate(pos, 200);
  
  				} else {
  					wrap.css(pos);
  
  					current.pos = $.extend({}, current.dim, pos);
  				}
  			}
  		},
  
  		update: function (e) {
  			var type = (e && e.originalEvent && e.originalEvent.type),
  				anyway = !type || type === 'orientationchange';
  
  			if (anyway) {
  				clearTimeout(didUpdate);
  
  				didUpdate = null;
  			}
  
  			if (!F.isOpen || didUpdate) {
  				return;
  			}
  
  			didUpdate = setTimeout(function() {
  				var current = F.current;
  
  				if (!current || F.isClosing) {
  					return;
  				}
  
  				F.wrap.removeClass('fancybox-tmp');
  
  				if (anyway || type === 'load' || (type === 'resize' && current.autoResize)) {
  					F._setDimension();
  				}
  
  				if (!(type === 'scroll' && current.canShrink)) {
  					F.reposition(e);
  				}
  
  				F.trigger('onUpdate');
  
  				didUpdate = null;
  
  			}, (anyway && !isTouch ? 0 : 300));
  		},
  
  		// Shrink content to fit inside viewport or restore if resized
  		toggle: function ( action ) {
  			if (F.isOpen) {
  				F.current.fitToView = $.type(action) === "boolean" ? action : !F.current.fitToView;
  
  				// Help browser to restore document dimensions
  				if (isTouch) {
  					F.wrap.removeAttr('style').addClass('fancybox-tmp');
  
  					F.trigger('onUpdate');
  				}
  
  				F.update();
  			}
  		},
  
  		hideLoading: function () {
  			D.unbind('.loading');
  
  			$('#fancybox-loading').remove();
  		},
  
  		showLoading: function () {
  			var el, viewport;
  
  			F.hideLoading();
  
  			el = $(F.opts.tpl.loading).click(F.cancel).appendTo('body');
  
  			// If user will press the escape-button, the request will be canceled
  			D.bind('keydown.loading', function(e) {
  				if ((e.which || e.keyCode) === 27) {
  					e.preventDefault();
  
  					F.cancel();
  				}
  			});
  
  			if (!F.defaults.fixed) {
  				viewport = F.getViewport();
  
  				el.css({
  					position : 'absolute',
  					top  : (viewport.h * 0.5) + viewport.y,
  					left : (viewport.w * 0.5) + viewport.x
  				});
  			}
  
  			F.trigger('onLoading');
  		},
  
  		getViewport: function () {
  			var locked = (F.current && F.current.locked) || false,
  				rez    = {
  					x: W.scrollLeft(),
  					y: W.scrollTop()
  				};
  
  			if (locked && locked.length) {
  				rez.w = locked[0].clientWidth;
  				rez.h = locked[0].clientHeight;
  
  			} else {
  				// See http://bugs.jquery.com/ticket/6724
  				rez.w = isTouch && window.innerWidth  ? window.innerWidth  : W.width();
  				rez.h = isTouch && window.innerHeight ? window.innerHeight : W.height();
  			}
  
  			return rez;
  		},
  
  		// Unbind the keyboard / clicking actions
  		unbindEvents: function () {
  			if (F.wrap && isQuery(F.wrap)) {
  				F.wrap.unbind('.fb');
  			}
  
  			D.unbind('.fb');
  			W.unbind('.fb');
  		},
  
  		bindEvents: function () {
  			var current = F.current,
  				keys;
  
  			if (!current) {
  				return;
  			}
  
  			// Changing document height on iOS devices triggers a 'resize' event,
  			// that can change document height... repeating infinitely
  			W.bind('orientationchange.fb' + (isTouch ? '' : ' resize.fb') + (current.autoCenter && !current.locked ? ' scroll.fb' : ''), F.update);
  
  			keys = current.keys;
  
  			if (keys) {
  				D.bind('keydown.fb', function (e) {
  					var code   = e.which || e.keyCode,
  						target = e.target || e.srcElement;
  
  					// Skip esc key if loading, because showLoading will cancel preloading
  					if (code === 27 && F.coming) {
  						return false;
  					}
  
  					// Ignore key combinations and key events within form elements
  					if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) {
  						$.each(keys, function(i, val) {
  							if (current.group.length > 1 && val[ code ] !== undefined) {
  								F[ i ]( val[ code ] );
  
  								e.preventDefault();
  								return false;
  							}
  
  							if ($.inArray(code, val) > -1) {
  								F[ i ] ();
  
  								e.preventDefault();
  								return false;
  							}
  						});
  					}
  				});
  			}
  
  			if ($.fn.mousewheel && current.mouseWheel) {
  				F.wrap.bind('mousewheel.fb', function (e, delta, deltaX, deltaY) {
  					var target = e.target || null,
  						parent = $(target),
  						canScroll = false;
  
  					while (parent.length) {
  						if (canScroll || parent.is('.fancybox-skin') || parent.is('.fancybox-wrap')) {
  							break;
  						}
  
  						canScroll = isScrollable( parent[0] );
  						parent    = $(parent).parent();
  					}
  
  					if (delta !== 0 && !canScroll) {
  						if (F.group.length > 1 && !current.canShrink) {
  							if (deltaY > 0 || deltaX > 0) {
  								F.prev( deltaY > 0 ? 'down' : 'left' );
  
  							} else if (deltaY < 0 || deltaX < 0) {
  								F.next( deltaY < 0 ? 'up' : 'right' );
  							}
  
  							e.preventDefault();
  						}
  					}
  				});
  			}
  		},
  
  		trigger: function (event, o) {
  			var ret, obj = o || F.coming || F.current;
  
  			if (obj) {
  				if ($.isFunction( obj[event] )) {
  					ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1));
  				}
  
  				if (ret === false) {
  					return false;
  				}
  
  				if (obj.helpers) {
  					$.each(obj.helpers, function (helper, opts) {
  						if (opts && F.helpers[helper] && $.isFunction(F.helpers[helper][event])) {
  							F.helpers[helper][event]($.extend(true, {}, F.helpers[helper].defaults, opts), obj);
  						}
  					});
  				}
  			}
  
  			D.trigger(event);
  		},
  
  		isImage: function (str) {
  			return isString(str) && str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i);
  		},
  
  		isSWF: function (str) {
  			return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i);
  		},
  
  		_start: function (index) {
  			var coming = {},
  				obj,
  				href,
  				type,
  				margin,
  				padding;
  
  			index = getScalar( index );
  			obj   = F.group[ index ] || null;
  
  			if (!obj) {
  				return false;
  			}
  
  			coming = $.extend(true, {}, F.opts, obj);
  
  			// Convert margin and padding properties to array - top, right, bottom, left
  			margin  = coming.margin;
  			padding = coming.padding;
  
  			if ($.type(margin) === 'number') {
  				coming.margin = [margin, margin, margin, margin];
  			}
  
  			if ($.type(padding) === 'number') {
  				coming.padding = [padding, padding, padding, padding];
  			}
  
  			// 'modal' propery is just a shortcut
  			if (coming.modal) {
  				$.extend(true, coming, {
  					closeBtn   : false,
  					closeClick : false,
  					nextClick  : false,
  					arrows     : false,
  					mouseWheel : false,
  					keys       : null,
  					helpers: {
  						overlay : {
  							closeClick : false
  						}
  					}
  				});
  			}
  
  			// 'autoSize' property is a shortcut, too
  			if (coming.autoSize) {
  				coming.autoWidth = coming.autoHeight = true;
  			}
  
  			if (coming.width === 'auto') {
  				coming.autoWidth = true;
  			}
  
  			if (coming.height === 'auto') {
  				coming.autoHeight = true;
  			}
  
  			/*
  			 * Add reference to the group, so it`s possible to access from callbacks, example:
  			 * afterLoad : function() {
  			 *     this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : '');
  			 * }
  			 */
  
  			coming.group  = F.group;
  			coming.index  = index;
  
  			// Give a chance for callback or helpers to update coming item (type, title, etc)
  			F.coming = coming;
  
  			if (false === F.trigger('beforeLoad')) {
  				F.coming = null;
  
  				return;
  			}
  
  			type = coming.type;
  			href = coming.href;
  
  			if (!type) {
  				F.coming = null;
  
  				//If we can not determine content type then drop silently or display next/prev item if looping through gallery
  				if (F.current && F.router && F.router !== 'jumpto') {
  					F.current.index = index;
  
  					return F[ F.router ]( F.direction );
  				}
  
  				return false;
  			}
  
  			F.isActive = true;
  
  			if (type === 'image' || type === 'swf') {
  				coming.autoHeight = coming.autoWidth = false;
  				coming.scrolling  = 'visible';
  			}
  
  			if (type === 'image') {
  				coming.aspectRatio = true;
  			}
  
  			if (type === 'iframe' && isTouch) {
  				coming.scrolling = 'scroll';
  			}
  
  			// Build the neccessary markup
  			coming.wrap = $(coming.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + type + ' fancybox-tmp ' + coming.wrapCSS).appendTo( coming.parent || 'body' );
  
  			$.extend(coming, {
  				skin  : $('.fancybox-skin',  coming.wrap),
  				outer : $('.fancybox-outer', coming.wrap),
  				inner : $('.fancybox-inner', coming.wrap)
  			});
  
  			$.each(["Top", "Right", "Bottom", "Left"], function(i, v) {
  				coming.skin.css('padding' + v, getValue(coming.padding[ i ]));
  			});
  
  			F.trigger('onReady');
  
  			// Check before try to load; 'inline' and 'html' types need content, others - href
  			if (type === 'inline' || type === 'html') {
  				if (!coming.content || !coming.content.length) {
  					return F._error( 'content' );
  				}
  
  			} else if (!href) {
  				return F._error( 'href' );
  			}
  
  			if (type === 'image') {
  				F._loadImage();
  
  			} else if (type === 'ajax') {
  				F._loadAjax();
  
  			} else if (type === 'iframe') {
  				F._loadIframe();
  
  			} else {
  				F._afterLoad();
  			}
  		},
  
  		_error: function ( type ) {
  			$.extend(F.coming, {
  				type       : 'html',
  				autoWidth  : true,
  				autoHeight : true,
  				minWidth   : 0,
  				minHeight  : 0,
  				scrolling  : 'no',
  				hasError   : type,
  				content    : F.coming.tpl.error
  			});
  
  			F._afterLoad();
  		},
  
  		_loadImage: function () {
  			// Reset preload image so it is later possible to check "complete" property
  			var img = F.imgPreload = new Image();
  
  			img.onload = function () {
  				this.onload = this.onerror = null;
  
  				F.coming.width  = this.width / F.opts.pixelRatio;
  				F.coming.height = this.height / F.opts.pixelRatio;
  
  				F._afterLoad();
  			};
  
  			img.onerror = function () {
  				this.onload = this.onerror = null;
  
  				F._error( 'image' );
  			};
  
  			img.src = F.coming.href;
  
  			if (img.complete !== true) {
  				F.showLoading();
  			}
  		},
  
  		_loadAjax: function () {
  			var coming = F.coming;
  
  			F.showLoading();
  
  			F.ajaxLoad = $.ajax($.extend({}, coming.ajax, {
  				url: coming.href,
  				error: function (jqXHR, textStatus) {
  					if (F.coming && textStatus !== 'abort') {
  						F._error( 'ajax', jqXHR );
  
  					} else {
  						F.hideLoading();
  					}
  				},
  				success: function (data, textStatus) {
  					if (textStatus === 'success') {
  						coming.content = data;
  
  						F._afterLoad();
  					}
  				}
  			}));
  		},
  
  		_loadIframe: function() {
  			var coming = F.coming,
  				iframe = $(coming.tpl.iframe.replace(/\{rnd\}/g, new Date().getTime()))
  					.attr('scrolling', isTouch ? 'auto' : coming.iframe.scrolling)
  					.attr('src', coming.href);
  
  			// This helps IE
  			$(coming.wrap).bind('onReset', function () {
  				try {
  					$(this).find('iframe').hide().attr('src', '//about:blank').end().empty();
  				} catch (e) {}
  			});
  
  			if (coming.iframe.preload) {
  				F.showLoading();
  
  				iframe.one('load', function() {
  					$(this).data('ready', 1);
  
  					// iOS will lose scrolling if we resize
  					if (!isTouch) {
  						$(this).bind('load.fb', F.update);
  					}
  
  					// Without this trick:
  					//   - iframe won't scroll on iOS devices
  					//   - IE7 sometimes displays empty iframe
  					$(this).parents('.fancybox-wrap').width('100%').removeClass('fancybox-tmp').show();
  
  					F._afterLoad();
  				});
  			}
  
  			coming.content = iframe.appendTo( coming.inner );
  
  			if (!coming.iframe.preload) {
  				F._afterLoad();
  			}
  		},
  
  		_preloadImages: function() {
  			var group   = F.group,
  				current = F.current,
  				len     = group.length,
  				cnt     = current.preload ? Math.min(current.preload, len - 1) : 0,
  				item,
  				i;
  
  			for (i = 1; i <= cnt; i += 1) {
  				item = group[ (current.index + i ) % len ];
  
  				if (item.type === 'image' && item.href) {
  					new Image().src = item.href;
  				}
  			}
  		},
  
  		_afterLoad: function () {
  			var coming   = F.coming,
  				previous = F.current,
  				placeholder = 'fancybox-placeholder',
  				current,
  				content,
  				type,
  				scrolling,
  				href,
  				embed;
  
  			F.hideLoading();
  
  			if (!coming || F.isActive === false) {
  				return;
  			}
  
  			if (false === F.trigger('afterLoad', coming, previous)) {
  				coming.wrap.stop(true).trigger('onReset').remove();
  
  				F.coming = null;
  
  				return;
  			}
  
  			if (previous) {
  				F.trigger('beforeChange', previous);
  
  				previous.wrap.stop(true).removeClass('fancybox-opened')
  					.find('.fancybox-item, .fancybox-nav')
  					.remove();
  			}
  
  			F.unbindEvents();
  
  			current   = coming;
  			content   = coming.content;
  			type      = coming.type;
  			scrolling = coming.scrolling;
  
  			$.extend(F, {
  				wrap  : current.wrap,
  				skin  : current.skin,
  				outer : current.outer,
  				inner : current.inner,
  				current  : current,
  				previous : previous
  			});
  
  			href = current.href;
  
  			switch (type) {
  				case 'inline':
  				case 'ajax':
  				case 'html':
  					if (current.selector) {
  						content = $('<div>').html(content).find(current.selector);
  
  					} else if (isQuery(content)) {
  						if (!content.data(placeholder)) {
  							content.data(placeholder, $('<div class="' + placeholder + '"></div>').insertAfter( content ).hide() );
  						}
  
  						content = content.show().detach();
  
  						current.wrap.bind('onReset', function () {
  							if ($(this).find(content).length) {
  								content.hide().replaceAll( content.data(placeholder) ).data(placeholder, false);
  							}
  						});
  					}
  				break;
  
  				case 'image':
  					content = current.tpl.image.replace(/\{href\}/g, href);
  				break;
  
  				case 'swf':
  					content = '<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="' + href + '"></param>';
  					embed   = '';
  
  					$.each(current.swf, function(name, val) {
  						content += '<param name="' + name + '" value="' + val + '"></param>';
  						embed   += ' ' + name + '="' + val + '"';
  					});
  
  					content += '<embed src="' + href + '" type="application/x-shockwave-flash" width="100%" height="100%"' + embed + '></embed></object>';
  				break;
  			}
  
  			if (!(isQuery(content) && content.parent().is(current.inner))) {
  				current.inner.append( content );
  			}
  
  			// Give a chance for helpers or callbacks to update elements
  			F.trigger('beforeShow');
  
  			// Set scrolling before calculating dimensions
  			current.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling));
  
  			// Set initial dimensions and start position
  			F._setDimension();
  
  			F.reposition();
  
  			F.isOpen = false;
  			F.coming = null;
  
  			F.bindEvents();
  
  			if (!F.isOpened) {
  				$('.fancybox-wrap').not( current.wrap ).stop(true).trigger('onReset').remove();
  
  			} else if (previous.prevMethod) {
  				F.transitions[ previous.prevMethod ]();
  			}
  
  			F.transitions[ F.isOpened ? current.nextMethod : current.openMethod ]();
  
  			F._preloadImages();
  		},
  
  		_setDimension: function () {
  			var viewport   = F.getViewport(),
  				steps      = 0,
  				canShrink  = false,
  				canExpand  = false,
  				wrap       = F.wrap,
  				skin       = F.skin,
  				inner      = F.inner,
  				current    = F.current,
  				width      = current.width,
  				height     = current.height,
  				minWidth   = current.minWidth,
  				minHeight  = current.minHeight,
  				maxWidth   = current.maxWidth,
  				maxHeight  = current.maxHeight,
  				scrolling  = current.scrolling,
  				scrollOut  = current.scrollOutside ? current.scrollbarWidth : 0,
  				margin     = current.margin,
  				wMargin    = getScalar(margin[1] + margin[3]),
  				hMargin    = getScalar(margin[0] + margin[2]),
  				wPadding,
  				hPadding,
  				wSpace,
  				hSpace,
  				origWidth,
  				origHeight,
  				origMaxWidth,
  				origMaxHeight,
  				ratio,
  				width_,
  				height_,
  				maxWidth_,
  				maxHeight_,
  				iframe,
  				body;
  
  			// Reset dimensions so we could re-check actual size
  			wrap.add(skin).add(inner).width('auto').height('auto').removeClass('fancybox-tmp');
  
  			wPadding = getScalar(skin.outerWidth(true)  - skin.width());
  			hPadding = getScalar(skin.outerHeight(true) - skin.height());
  
  			// Any space between content and viewport (margin, padding, border, title)
  			wSpace = wMargin + wPadding;
  			hSpace = hMargin + hPadding;
  
  			origWidth  = isPercentage(width)  ? (viewport.w - wSpace) * getScalar(width)  / 100 : width;
  			origHeight = isPercentage(height) ? (viewport.h - hSpace) * getScalar(height) / 100 : height;
  
  			if (current.type === 'iframe') {
  				iframe = current.content;
  
  				if (current.autoHeight && iframe.data('ready') === 1) {
  					try {
  						if (iframe[0].contentWindow.document.location) {
  							inner.width( origWidth ).height(9999);
  
  							body = iframe.contents().find('body');
  
  							if (scrollOut) {
  								body.css('overflow-x', 'hidden');
  							}
  
  							origHeight = body.outerHeight(true);
  						}
  
  					} catch (e) {}
  				}
  
  			} else if (current.autoWidth || current.autoHeight) {
  				inner.addClass( 'fancybox-tmp' );
  
  				// Set width or height in case we need to calculate only one dimension
  				if (!current.autoWidth) {
  					inner.width( origWidth );
  				}
  
  				if (!current.autoHeight) {
  					inner.height( origHeight );
  				}
  
  				if (current.autoWidth) {
  					origWidth = inner.width();
  				}
  
  				if (current.autoHeight) {
  					origHeight = inner.height();
  				}
  
  				inner.removeClass( 'fancybox-tmp' );
  			}
  
  			width  = getScalar( origWidth );
  			height = getScalar( origHeight );
  
  			ratio  = origWidth / origHeight;
  
  			// Calculations for the content
  			minWidth  = getScalar(isPercentage(minWidth) ? getScalar(minWidth, 'w') - wSpace : minWidth);
  			maxWidth  = getScalar(isPercentage(maxWidth) ? getScalar(maxWidth, 'w') - wSpace : maxWidth);
  
  			minHeight = getScalar(isPercentage(minHeight) ? getScalar(minHeight, 'h') - hSpace : minHeight);
  			maxHeight = getScalar(isPercentage(maxHeight) ? getScalar(maxHeight, 'h') - hSpace : maxHeight);
  
  			// These will be used to determine if wrap can fit in the viewport
  			origMaxWidth  = maxWidth;
  			origMaxHeight = maxHeight;
  
  			if (current.fitToView) {
  				maxWidth  = Math.min(viewport.w - wSpace, maxWidth);
  				maxHeight = Math.min(viewport.h - hSpace, maxHeight);
  			}
  
  			maxWidth_  = viewport.w - wMargin;
  			maxHeight_ = viewport.h - hMargin;
  
  			if (current.aspectRatio) {
  				if (width > maxWidth) {
  					width  = maxWidth;
  					height = getScalar(width / ratio);
  				}
  
  				if (height > maxHeight) {
  					height = maxHeight;
  					width  = getScalar(height * ratio);
  				}
  
  				if (width < minWidth) {
  					width  = minWidth;
  					height = getScalar(width / ratio);
  				}
  
  				if (height < minHeight) {
  					height = minHeight;
  					width  = getScalar(height * ratio);
  				}
  
  			} else {
  				width = Math.max(minWidth, Math.min(width, maxWidth));
  
  				if (current.autoHeight && current.type !== 'iframe') {
  					inner.width( width );
  
  					height = inner.height();
  				}
  
  				height = Math.max(minHeight, Math.min(height, maxHeight));
  			}
  
  			// Try to fit inside viewport (including the title)
  			if (current.fitToView) {
  				inner.width( width ).height( height );
  
  				wrap.width( width + wPadding );
  
  				// Real wrap dimensions
  				width_  = wrap.width();
  				height_ = wrap.height();
  
  				if (current.aspectRatio) {
  					while ((width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight) {
  						if (steps++ > 19) {
  							break;
  						}
  
  						height = Math.max(minHeight, Math.min(maxHeight, height - 10));
  						width  = getScalar(height * ratio);
  
  						if (width < minWidth) {
  							width  = minWidth;
  							height = getScalar(width / ratio);
  						}
  
  						if (width > maxWidth) {
  							width  = maxWidth;
  							height = getScalar(width / ratio);
  						}
  
  						inner.width( width ).height( height );
  
  						wrap.width( width + wPadding );
  
  						width_  = wrap.width();
  						height_ = wrap.height();
  					}
  
  				} else {
  					width  = Math.max(minWidth,  Math.min(width,  width  - (width_  - maxWidth_)));
  					height = Math.max(minHeight, Math.min(height, height - (height_ - maxHeight_)));
  				}
  			}
  
  			if (scrollOut && scrolling === 'auto' && height < origHeight && (width + wPadding + scrollOut) < maxWidth_) {
  				width += scrollOut;
  			}
  
  			inner.width( width ).height( height );
  
  			wrap.width( width + wPadding );
  
  			width_  = wrap.width();
  			height_ = wrap.height();
  
  			canShrink = (width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight;
  			canExpand = current.aspectRatio ? (width < origMaxWidth && height < origMaxHeight && width < origWidth && height < origHeight) : ((width < origMaxWidth || height < origMaxHeight) && (width < origWidth || height < origHeight));
  
  			$.extend(current, {
  				dim : {
  					width	: getValue( width_ ),
  					height	: getValue( height_ )
  				},
  				origWidth  : origWidth,
  				origHeight : origHeight,
  				canShrink  : canShrink,
  				canExpand  : canExpand,
  				wPadding   : wPadding,
  				hPadding   : hPadding,
  				wrapSpace  : height_ - skin.outerHeight(true),
  				skinSpace  : skin.height() - height
  			});
  
  			if (!iframe && current.autoHeight && height > minHeight && height < maxHeight && !canExpand) {
  				inner.height('auto');
  			}
  		},
  
  		_getPosition: function (onlyAbsolute) {
  			var current  = F.current,
  				viewport = F.getViewport(),
  				margin   = current.margin,
  				width    = F.wrap.width()  + margin[1] + margin[3],
  				height   = F.wrap.height() + margin[0] + margin[2],
  				rez      = {
  					position: 'absolute',
  					top  : margin[0],
  					left : margin[3]
  				};
  
  			if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) {
  				rez.position = 'fixed';
  
  			} else if (!current.locked) {
  				rez.top  += viewport.y;
  				rez.left += viewport.x;
  			}
  
  			rez.top  = getValue(Math.max(rez.top,  rez.top  + ((viewport.h - height) * current.topRatio)));
  			rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width)  * current.leftRatio)));
  
  			return rez;
  		},
  
  		_afterZoomIn: function () {
  			var current = F.current;
  
  			if (!current) {
  				return;
  			}
  
  			F.isOpen = F.isOpened = true;
  
  			F.wrap.css('overflow', 'visible').addClass('fancybox-opened').hide().show(0);
  
  			F.update();
  
  			// Assign a click event
  			if ( current.closeClick || (current.nextClick && F.group.length > 1) ) {
  				F.inner.css('cursor', 'pointer').bind('click.fb', function(e) {
  					if (!$(e.target).is('a') && !$(e.target).parent().is('a')) {
  						e.preventDefault();
  
  						F[ current.closeClick ? 'close' : 'next' ]();
  					}
  				});
  			}
  
  			// Create a close button
  			if (current.closeBtn) {
  				$(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', function(e) {
  					e.preventDefault();
  
  					F.close();
  				});
  			}
  
  			// Create navigation arrows
  			if (current.arrows && F.group.length > 1) {
  				if (current.loop || current.index > 0) {
  					$(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev);
  				}
  
  				if (current.loop || current.index < F.group.length - 1) {
  					$(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next);
  				}
  			}
  
  			F.trigger('afterShow');
  
  			// Stop the slideshow if this is the last item
  			if (!current.loop && current.index === current.group.length - 1) {
  
  				F.play( false );
  
  			} else if (F.opts.autoPlay && !F.player.isActive) {
  				F.opts.autoPlay = false;
  
  				F.play(true);
  			}
  		},
  
  		_afterZoomOut: function ( obj ) {
  			obj = obj || F.current;
  
  			$('.fancybox-wrap').trigger('onReset').remove();
  
  			$.extend(F, {
  				group  : {},
  				opts   : {},
  				router : false,
  				current   : null,
  				isActive  : false,
  				isOpened  : false,
  				isOpen    : false,
  				isClosing : false,
  				wrap   : null,
  				skin   : null,
  				outer  : null,
  				inner  : null
  			});
  
  			F.trigger('afterClose', obj);
  		}
  	});
  
  	/*
  	 *	Default transitions
  	 */
  
  	F.transitions = {
  		getOrigPosition: function () {
  			var current  = F.current,
  				element  = current.element,
  				orig     = current.orig,
  				pos      = {},
  				width    = 50,
  				height   = 50,
  				hPadding = current.hPadding,
  				wPadding = current.wPadding,
  				viewport = F.getViewport();
  
  			if (!orig && current.isDom && element.is(':visible')) {
  				orig = element.find('img:first');
  
  				if (!orig.length) {
  					orig = element;
  				}
  			}
  
  			if (isQuery(orig)) {
  				pos = orig.offset();
  
  				if (orig.is('img')) {
  					width  = orig.outerWidth();
  					height = orig.outerHeight();
  				}
  
  			} else {
  				pos.top  = viewport.y + (viewport.h - height) * current.topRatio;
  				pos.left = viewport.x + (viewport.w - width)  * current.leftRatio;
  			}
  
  			if (F.wrap.css('position') === 'fixed' || current.locked) {
  				pos.top  -= viewport.y;
  				pos.left -= viewport.x;
  			}
  
  			pos = {
  				top     : getValue(pos.top  - hPadding * current.topRatio),
  				left    : getValue(pos.left - wPadding * current.leftRatio),
  				width   : getValue(width  + wPadding),
  				height  : getValue(height + hPadding)
  			};
  
  			return pos;
  		},
  
  		step: function (now, fx) {
  			var ratio,
  				padding,
  				value,
  				prop       = fx.prop,
  				current    = F.current,
  				wrapSpace  = current.wrapSpace,
  				skinSpace  = current.skinSpace;
  
  			if (prop === 'width' || prop === 'height') {
  				ratio = fx.end === fx.start ? 1 : (now - fx.start) / (fx.end - fx.start);
  
  				if (F.isClosing) {
  					ratio = 1 - ratio;
  				}
  
  				padding = prop === 'width' ? current.wPadding : current.hPadding;
  				value   = now - padding;
  
  				F.skin[ prop ](  getScalar( prop === 'width' ?  value : value - (wrapSpace * ratio) ) );
  				F.inner[ prop ]( getScalar( prop === 'width' ?  value : value - (wrapSpace * ratio) - (skinSpace * ratio) ) );
  			}
  		},
  
  		zoomIn: function () {
  			var current  = F.current,
  				startPos = current.pos,
  				effect   = current.openEffect,
  				elastic  = effect === 'elastic',
  				endPos   = $.extend({opacity : 1}, startPos);
  
  			// Remove "position" property that breaks older IE
  			delete endPos.position;
  
  			if (elastic) {
  				startPos = this.getOrigPosition();
  
  				if (current.openOpacity) {
  					startPos.opacity = 0.1;
  				}
  
  			} else if (effect === 'fade') {
  				startPos.opacity = 0.1;
  			}
  
  			F.wrap.css(startPos).animate(endPos, {
  				duration : effect === 'none' ? 0 : current.openSpeed,
  				easing   : current.openEasing,
  				step     : elastic ? this.step : null,
  				complete : F._afterZoomIn
  			});
  		},
  
  		zoomOut: function () {
  			var current  = F.current,
  				effect   = current.closeEffect,
  				elastic  = effect === 'elastic',
  				endPos   = {opacity : 0.1};
  
  			if (elastic) {
  				endPos = this.getOrigPosition();
  
  				if (current.closeOpacity) {
  					endPos.opacity = 0.1;
  				}
  			}
  
  			F.wrap.animate(endPos, {
  				duration : effect === 'none' ? 0 : current.closeSpeed,
  				easing   : current.closeEasing,
  				step     : elastic ? this.step : null,
  				complete : F._afterZoomOut
  			});
  		},
  
  		changeIn: function () {
  			var current   = F.current,
  				effect    = current.nextEffect,
  				startPos  = current.pos,
  				endPos    = { opacity : 1 },
  				direction = F.direction,
  				distance  = 200,
  				field;
  
  			startPos.opacity = 0.1;
  
  			if (effect === 'elastic') {
  				field = direction === 'down' || direction === 'up' ? 'top' : 'left';
  
  				if (direction === 'down' || direction === 'right') {
  					startPos[ field ] = getValue(getScalar(startPos[ field ]) - distance);
  					endPos[ field ]   = '+=' + distance + 'px';
  
  				} else {
  					startPos[ field ] = getValue(getScalar(startPos[ field ]) + distance);
  					endPos[ field ]   = '-=' + distance + 'px';
  				}
  			}
  
  			// Workaround for http://bugs.jquery.com/ticket/12273
  			if (effect === 'none') {
  				F._afterZoomIn();
  
  			} else {
  				F.wrap.css(startPos).animate(endPos, {
  					duration : current.nextSpeed,
  					easing   : current.nextEasing,
  					complete : F._afterZoomIn
  				});
  			}
  		},
  
  		changeOut: function () {
  			var previous  = F.previous,
  				effect    = previous.prevEffect,
  				endPos    = { opacity : 0.1 },
  				direction = F.direction,
  				distance  = 200;
  
  			if (effect === 'elastic') {
  				endPos[ direction === 'down' || direction === 'up' ? 'top' : 'left' ] = ( direction === 'up' || direction === 'left' ? '-' : '+' ) + '=' + distance + 'px';
  			}
  
  			previous.wrap.animate(endPos, {
  				duration : effect === 'none' ? 0 : previous.prevSpeed,
  				easing   : previous.prevEasing,
  				complete : function () {
  					$(this).trigger('onReset').remove();
  				}
  			});
  		}
  	};
  
  	/*
  	 *	Overlay helper
  	 */
  
  	F.helpers.overlay = {
  		defaults : {
  			closeClick : true,      // if true, fancyBox will be closed when user clicks on the overlay
  			speedOut   : 200,       // duration of fadeOut animation
  			showEarly  : true,      // indicates if should be opened immediately or wait until the content is ready
  			css        : {},        // custom CSS properties
  			locked     : !isTouch,  // if true, the content will be locked into overlay
  			fixed      : true       // if false, the overlay CSS position property will not be set to "fixed"
  		},
  
  		overlay : null,      // current handle
  		fixed   : false,     // indicates if the overlay has position "fixed"
  		el      : $('html'), // element that contains "the lock"
  
  		// Public methods
  		create : function(opts) {
  			var parent;
  
  			opts = $.extend({}, this.defaults, opts);
  
  			if (this.overlay) {
  				this.close();
  			}
  
  			parent = F.coming ? F.coming.parent : opts.parent;
  
  			this.overlay = $('<div class="fancybox-overlay"></div>').appendTo( parent && parent.length ? parent : 'body' );
  			this.fixed   = false;
  
  			if (opts.fixed && F.defaults.fixed) {
  				this.overlay.addClass('fancybox-overlay-fixed');
  
  				this.fixed = true;
  			}
  		},
  
  		open : function(opts) {
  			var that = this;
  
  			opts = $.extend({}, this.defaults, opts);
  
  			if (this.overlay) {
  				this.overlay.unbind('.overlay').width('auto').height('auto');
  
  			} else {
  				this.create(opts);
  			}
  
  			if (!this.fixed) {
  				W.bind('resize.overlay', $.proxy( this.update, this) );
  
  				this.update();
  			}
  
  			if (opts.closeClick) {
  				this.overlay.bind('click.overlay', function(e) {
  					if ($(e.target).hasClass('fancybox-overlay')) {
  						if (F.isActive) {
  							F.close();
  						} else {
  							that.close();
  						}
  
  						return false;
  					}
  				});
  			}
  
  			this.overlay.css( opts.css ).show();
  		},
  
  		close : function() {
  			W.unbind('resize.overlay');
  
  			if (this.el.hasClass('fancybox-lock')) {
  				$('.fancybox-margin').removeClass('fancybox-margin');
  
  				this.el.removeClass('fancybox-lock');
  
  				W.scrollTop( this.scrollV ).scrollLeft( this.scrollH );
  			}
  
  			$('.fancybox-overlay').remove().hide();
  
  			$.extend(this, {
  				overlay : null,
  				fixed   : false
  			});
  		},
  
  		// Private, callbacks
  
  		update : function () {
  			var width = '100%', offsetWidth;
  
  			// Reset width/height so it will not mess
  			this.overlay.width(width).height('100%');
  
  			// jQuery does not return reliable result for IE
  			if (IE) {
  				offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth);
  
  				if (D.width() > offsetWidth) {
  					width = D.width();
  				}
  
  			} else if (D.width() > W.width()) {
  				width = D.width();
  			}
  
  			this.overlay.width(width).height(D.height());
  		},
  
  		// This is where we can manipulate DOM, because later it would cause iframes to reload
  		onReady : function (opts, obj) {
  			var overlay = this.overlay;
  
  			$('.fancybox-overlay').stop(true, true);
  
  			if (!overlay) {
  				this.create(opts);
  			}
  
  			if (opts.locked && this.fixed && obj.fixed) {
  				obj.locked = this.overlay.append( obj.wrap );
  				obj.fixed  = false;
  			}
  
  			if (opts.showEarly === true) {
  				this.beforeShow.apply(this, arguments);
  			}
  		},
  
  		beforeShow : function(opts, obj) {
  			if (obj.locked && !this.el.hasClass('fancybox-lock')) {
  				if (this.fixPosition !== false) {
  					$('*').filter(function(){
  						return ($(this).css('position') === 'fixed' && !$(this).hasClass("fancybox-overlay") && !$(this).hasClass("fancybox-wrap") );
  					}).addClass('fancybox-margin');
  				}
  
  				this.el.addClass('fancybox-margin');
  
  				this.scrollV = W.scrollTop();
  				this.scrollH = W.scrollLeft();
  
  				this.el.addClass('fancybox-lock');
  
  				W.scrollTop( this.scrollV ).scrollLeft( this.scrollH );
  			}
  
  			this.open(opts);
  		},
  
  		onUpdate : function() {
  			if (!this.fixed) {
  				this.update();
  			}
  		},
  
  		afterClose: function (opts) {
  			// Remove overlay if exists and fancyBox is not opening
  			// (e.g., it is not being open using afterClose callback)
  			if (this.overlay && !F.coming) {
  				this.overlay.fadeOut(opts.speedOut, $.proxy( this.close, this ));
  			}
  		}
  	};
  
  	/*
  	 *	Title helper
  	 */
  
  	F.helpers.title = {
  		defaults : {
  			type     : 'float', // 'float', 'inside', 'outside' or 'over',
  			position : 'bottom' // 'top' or 'bottom'
  		},
  
  		beforeShow: function (opts) {
  			var current = F.current,
  				text    = current.title,
  				type    = opts.type,
  				title,
  				target;
  
  			if ($.isFunction(text)) {
  				text = text.call(current.element, current);
  			}
  
  			if (!isString(text) || $.trim(text) === '') {
  				return;
  			}
  
  			title = $('<div class="fancybox-title fancybox-title-' + type + '-wrap">' + text + '</div>');
  
  			switch (type) {
  				case 'inside':
  					target = F.skin;
  				break;
  
  				case 'outside':
  					target = F.wrap;
  				break;
  
  				case 'over':
  					target = F.inner;
  				break;
  
  				default: // 'float'
  					target = F.skin;
  
  					title.appendTo('body');
  
  					if (IE) {
  						title.width( title.width() );
  					}
  
  					title.wrapInner('<span class="child"></span>');
  
  					//Increase bottom margin so this title will also fit into viewport
  					F.current.margin[2] += Math.abs( getScalar(title.css('margin-bottom')) );
  				break;
  			}
  
  			title[ (opts.position === 'top' ? 'prependTo'  : 'appendTo') ](target);
  		}
  	};
  
  	// jQuery plugin initialization
  	$.fn.fancybox = function (options) {
  		var index,
  			that     = $(this),
  			selector = this.selector || '',
  			run      = function(e) {
  				var what = $(this).blur(), idx = index, relType, relVal;
  
  				if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !what.is('.fancybox-wrap')) {
  					relType = options.groupAttr || 'data-fancybox-group';
  					relVal  = what.attr(relType);
  
  					if (!relVal) {
  						relType = 'rel';
  						relVal  = what.get(0)[ relType ];
  					}
  
  					if (relVal && relVal !== '' && relVal !== 'nofollow') {
  						what = selector.length ? $(selector) : that;
  						what = what.filter('[' + relType + '="' + relVal + '"]');
  						idx  = what.index(this);
  					}
  
  					options.index = idx;
  
  					// Stop an event from bubbling if everything is fine
  					if (F.open(what, options) !== false) {
  						e.preventDefault();
  					}
  				}
  			};
  
  		options = options || {};
  		index   = options.index || 0;
  
  		if (!selector || options.live === false) {
  			that.off('click.fb-start').on('click.fb-start', run);
  
  		} else {
  			D.undelegate(selector, 'click.fb-start').delegate(selector + ":not('.fancybox-item, .fancybox-nav')", 'click.fb-start', run);
  		}
  
  		this.filter('[data-fancybox-start=1]').trigger('click');
  
  		return this;
  	};
  
  	// Tests that need a body at doc ready
  	D.ready(function() {
  		var w1, w2;
  
  		if ( $.scrollbarWidth === undefined ) {
  			// http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth
  			$.scrollbarWidth = function() {
  				var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body'),
  					child  = parent.children(),
  					width  = child.innerWidth() - child.height( 99 ).innerWidth();
  
  				parent.remove();
  
  				return width;
  			};
  		}
  
  		if ( $.support.fixedPosition === undefined ) {
  			$.support.fixedPosition = (function() {
  				var elem  = $('<div style="position:fixed;top:20px;"></div>').appendTo('body'),
  					fixed = ( elem[0].offsetTop === 20 || elem[0].offsetTop === 15 );
  
  				elem.remove();
  
  				return fixed;
  			}());
  		}
  
  		$.extend(F.defaults, {
  			scrollbarWidth : $.scrollbarWidth(),
  			fixed  : $.support.fixedPosition,
  			parent : $('body')
  		});
  
  		//Get real width of page scroll-bar
  		w1 = $(window).width();
  
  		H.addClass('fancybox-lock-test');
  
  		w2 = $(window).width();
  
  		H.removeClass('fancybox-lock-test');
  
  		$("<style type='text/css'>.fancybox-margin{margin-right:" + (w2 - w1) + "px;}</style>").appendTo("head");
  	});
  
  }(window, document, jQuery));
  
  // Generated by CoffeeScript 1.4.0
  
  /*
  eqHeight.coffee v1.2.3
  http://jsliang.github.com/eqHeight.coffee
  
  Copyright (c) 2013, Jui-Shan Liang <jenny@jsliang.com>
  All rights reserved.
  Licensed under GPL v2.
  */
  
  
  (function() {
    var $;
  
    $ = jQuery;
  
    $.fn.extend({
      eqHeight: function(column_selector) {
        return this.each(function() {
          var columns, equalizer, _equalize_marked_columns;
          columns = $(this).find(column_selector);
          if (columns.length === 0) {
            columns = $(this).children(column_selector);
          }
          if (columns.length === 0) {
            return;
          }
          _equalize_marked_columns = function() {
            var marked_columns, max_col_height;
            marked_columns = $(".eqHeight_row");
            max_col_height = 0;
            marked_columns.each(function() {
              if ($(this).height() > max_col_height) {
                return max_col_height = $(this).height();
              }
            });
            marked_columns.height(max_col_height);
            return $(".eqHeight_row").removeClass("eqHeight_row");
          };
          equalizer = function() {
            var row_top_value;
            columns.height("auto");
            row_top_value = columns.first().position().top;
            columns.each(function() {
              var current_top;
              current_top = $(this).position().top;
              if (current_top !== row_top_value) {
                _equalize_marked_columns();
                row_top_value = $(this).position().top;
              }
              return $(this).addClass("eqHeight_row");
            });
            return _equalize_marked_columns();
          };
          $(window).on("load", equalizer);
          return $(window).on("resize", equalizer);
        });
      }
    });
  
  }).call(this);
  
  
  (function(root, factory) {
    if (typeof define === 'function' && define.amd) {
      define(factory);
    } else if (typeof exports === 'object') {
      module.exports = factory(require, exports, module);
    } else {
      root.CountUp = factory();
    }
  }(this, function(require, exports, module) {
  
  /*
  
      countUp.js
      (c) 2014-2015 @inorganik
      Licensed under the MIT license.
  
  */
  
  // target = id of html element or var of previously selected html element where counting occurs
  // startVal = the value you want to begin at
  // endVal = the value you want to arrive at
  // decimals = number of decimal places, default 0
  // duration = duration of animation in seconds, default 2
  // options = optional object of options (see below)
  
  var CountUp = function(target, startVal, endVal, decimals, duration, options) {
  
      // make sure requestAnimationFrame and cancelAnimationFrame are defined
      // polyfill for browsers without native support
      // by Opera engineer Erik Möller
      var lastTime = 0;
      var vendors = ['webkit', 'moz', 'ms', 'o'];
      for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
          window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
          window.cancelAnimationFrame =
            window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
      }
      if (!window.requestAnimationFrame) {
          window.requestAnimationFrame = function(callback, element) {
              var currTime = new Date().getTime();
              var timeToCall = Math.max(0, 16 - (currTime - lastTime));
              var id = window.setTimeout(function() { callback(currTime + timeToCall); },
                timeToCall);
              lastTime = currTime + timeToCall;
              return id;
          };
      }
      if (!window.cancelAnimationFrame) {
          window.cancelAnimationFrame = function(id) {
              clearTimeout(id);
          };
      }
  
       // default options
      this.options = {
          useEasing : true, // toggle easing
          useGrouping : true, // 1,000,000 vs 1000000
          separator : ',', // character to use as a separator
          decimal : '.' // character to use as a decimal
      };
      // extend default options with passed options object
      for (var key in options) {
          if (options.hasOwnProperty(key)) {
              this.options[key] = options[key];
          }
      }
      if (this.options.separator === '') this.options.useGrouping = false;
      if (!this.options.prefix) this.options.prefix = '';
      if (!this.options.suffix) this.options.suffix = '';
  
      this.d = (typeof target === 'string') ? document.getElementById(target) : target;
      this.startVal = Number(startVal);
      this.endVal = Number(endVal);
      this.countDown = (this.startVal > this.endVal);
      this.frameVal = this.startVal;
      this.decimals = Math.max(0, decimals || 0);
      this.dec = Math.pow(10, this.decimals);
      this.duration = Number(duration) * 1000 || 2000;
      var self = this;
  
      this.version = function () { return '1.6.0'; };
  
      // Print value to target
      this.printValue = function(value) {
          var result = (!isNaN(value)) ? self.formatNumber(value) : '--';
          if (self.d.tagName == 'INPUT') {
              this.d.value = result;
          }
          else if (self.d.tagName == 'text' || self.d.tagName == 'tspan') {
              this.d.textContent = result;
          }
          else {
              this.d.innerHTML = result;
          }
      };
  
      // Robert Penner's easeOutExpo
      this.easeOutExpo = function(t, b, c, d) {
          return c * (-Math.pow(2, -10 * t / d) + 1) * 1024 / 1023 + b;
      };
      this.count = function(timestamp) {
  
          if (!self.startTime) self.startTime = timestamp;
  
          self.timestamp = timestamp;
  
          var progress = timestamp - self.startTime;
          self.remaining = self.duration - progress;
  
          // to ease or not to ease
          if (self.options.useEasing) {
              if (self.countDown) {
                  self.frameVal = self.startVal - self.easeOutExpo(progress, 0, self.startVal - self.endVal, self.duration);
              } else {
                  self.frameVal = self.easeOutExpo(progress, self.startVal, self.endVal - self.startVal, self.duration);
              }
          } else {
              if (self.countDown) {
                  self.frameVal = self.startVal - ((self.startVal - self.endVal) * (progress / self.duration));
              } else {
                  self.frameVal = self.startVal + (self.endVal - self.startVal) * (progress / self.duration);
              }
          }
  
          // don't go past endVal since progress can exceed duration in the last frame
          if (self.countDown) {
              self.frameVal = (self.frameVal < self.endVal) ? self.endVal : self.frameVal;
          } else {
              self.frameVal = (self.frameVal > self.endVal) ? self.endVal : self.frameVal;
          }
  
          // decimal
          self.frameVal = Math.round(self.frameVal*self.dec)/self.dec;
  
          // format and print value
          self.printValue(self.frameVal);
  
          // whether to continue
          if (progress < self.duration) {
              self.rAF = requestAnimationFrame(self.count);
          } else {
              if (self.callback) self.callback();
          }
      };
      // start your animation
      this.start = function(callback) {
          self.callback = callback;
          self.rAF = requestAnimationFrame(self.count);
          return false;
      };
      // toggles pause/resume animation
      this.pauseResume = function() {
          if (!self.paused) {
              self.paused = true;
              cancelAnimationFrame(self.rAF);
          } else {
              self.paused = false;
              delete self.startTime;
              self.duration = self.remaining;
              self.startVal = self.frameVal;
              requestAnimationFrame(self.count);
          }
      };
      // reset to startVal so animation can be run again
      this.reset = function() {
          self.paused = false;
          delete self.startTime;
          self.startVal = startVal;
          cancelAnimationFrame(self.rAF);
          self.printValue(self.startVal);
      };
      // pass a new endVal and start animation
      this.update = function (newEndVal) {
          cancelAnimationFrame(self.rAF);
          self.paused = false;
          delete self.startTime;
          self.startVal = self.frameVal;
          self.endVal = Number(newEndVal);
          self.countDown = (self.startVal > self.endVal);
          self.rAF = requestAnimationFrame(self.count);
      };
      this.formatNumber = function(nStr) {
          nStr = nStr.toFixed(self.decimals);
          nStr += '';
          var x, x1, x2, rgx;
          x = nStr.split('.');
          x1 = x[0];
          x2 = x.length > 1 ? self.options.decimal + x[1] : '';
          rgx = /(\d+)(\d{3})/;
          if (self.options.useGrouping) {
              while (rgx.test(x1)) {
                  x1 = x1.replace(rgx, '$1' + self.options.separator + '$2');
              }
          }
          return self.options.prefix + x1 + x2 + self.options.suffix;
      };
  
      // format startVal on initialization
      self.printValue(self.startVal);
  };
  
  // Example:
  // var numAnim = new countUp("SomeElementYouWantToAnimate", 0, 99.99, 2, 2.5);
  // numAnim.start();
  // numAnim.update(135);
  // with optional callback:
  // numAnim.start(someMethodToCallOnComplete);
  
  return CountUp;
  
  }));
  
  /*!
  Waypoints - 4.0.0
  Copyright © 2011-2015 Caleb Troughton
  Licensed under the MIT license.
  https://github.com/imakewebthings/waypoints/blog/master/licenses.txt
  */
  (function() {
    'use strict'
  
    var keyCounter = 0
    var allWaypoints = {}
  
    /* http://imakewebthings.com/waypoints/api/waypoint */
    function Waypoint(options) {
      if (!options) {
        throw new Error('No options passed to Waypoint constructor')
      }
      if (!options.element) {
        throw new Error('No element option passed to Waypoint constructor')
      }
      if (!options.handler) {
        throw new Error('No handler option passed to Waypoint constructor')
      }
  
      this.key = 'waypoint-' + keyCounter
      this.options = Waypoint.Adapter.extend({}, Waypoint.defaults, options)
      this.element = this.options.element
      this.adapter = new Waypoint.Adapter(this.element)
      this.callback = options.handler
      this.axis = this.options.horizontal ? 'horizontal' : 'vertical'
      this.enabled = this.options.enabled
      this.triggerPoint = null
      this.group = Waypoint.Group.findOrCreate({
        name: this.options.group,
        axis: this.axis
      })
      this.context = Waypoint.Context.findOrCreateByElement(this.options.context)
  
      if (Waypoint.offsetAliases[this.options.offset]) {
        this.options.offset = Waypoint.offsetAliases[this.options.offset]
      }
      this.group.add(this)
      this.context.add(this)
      allWaypoints[this.key] = this
      keyCounter += 1
    }
  
    /* Private */
    Waypoint.prototype.queueTrigger = function(direction) {
      this.group.queueTrigger(this, direction)
    }
  
    /* Private */
    Waypoint.prototype.trigger = function(args) {
      if (!this.enabled) {
        return
      }
      if (this.callback) {
        this.callback.apply(this, args)
      }
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/destroy */
    Waypoint.prototype.destroy = function() {
      this.context.remove(this)
      this.group.remove(this)
      delete allWaypoints[this.key]
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/disable */
    Waypoint.prototype.disable = function() {
      this.enabled = false
      return this
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/enable */
    Waypoint.prototype.enable = function() {
      this.context.refresh()
      this.enabled = true
      return this
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/next */
    Waypoint.prototype.next = function() {
      return this.group.next(this)
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/previous */
    Waypoint.prototype.previous = function() {
      return this.group.previous(this)
    }
  
    /* Private */
    Waypoint.invokeAll = function(method) {
      var allWaypointsArray = []
      for (var waypointKey in allWaypoints) {
        allWaypointsArray.push(allWaypoints[waypointKey])
      }
      for (var i = 0, end = allWaypointsArray.length; i < end; i++) {
        allWaypointsArray[i][method]()
      }
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/destroy-all */
    Waypoint.destroyAll = function() {
      Waypoint.invokeAll('destroy')
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/disable-all */
    Waypoint.disableAll = function() {
      Waypoint.invokeAll('disable')
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/enable-all */
    Waypoint.enableAll = function() {
      Waypoint.invokeAll('enable')
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/refresh-all */
    Waypoint.refreshAll = function() {
      Waypoint.Context.refreshAll()
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/viewport-height */
    Waypoint.viewportHeight = function() {
      return window.innerHeight || document.documentElement.clientHeight
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/viewport-width */
    Waypoint.viewportWidth = function() {
      return document.documentElement.clientWidth
    }
  
    Waypoint.adapters = []
  
    Waypoint.defaults = {
      context: window,
      continuous: true,
      enabled: true,
      group: 'default',
      horizontal: false,
      offset: 0
    }
  
    Waypoint.offsetAliases = {
      'bottom-in-view': function() {
        return this.context.innerHeight() - this.adapter.outerHeight()
      },
      'right-in-view': function() {
        return this.context.innerWidth() - this.adapter.outerWidth()
      }
    }
  
    window.Waypoint = Waypoint
  }())
  ;(function() {
    'use strict'
  
    function requestAnimationFrameShim(callback) {
      window.setTimeout(callback, 1000 / 60)
    }
  
    var keyCounter = 0
    var contexts = {}
    var Waypoint = window.Waypoint
    var oldWindowLoad = window.onload
  
    /* http://imakewebthings.com/waypoints/api/context */
    function Context(element) {
      this.element = element
      this.Adapter = Waypoint.Adapter
      this.adapter = new this.Adapter(element)
      this.key = 'waypoint-context-' + keyCounter
      this.didScroll = false
      this.didResize = false
      this.oldScroll = {
        x: this.adapter.scrollLeft(),
        y: this.adapter.scrollTop()
      }
      this.waypoints = {
        vertical: {},
        horizontal: {}
      }
  
      element.waypointContextKey = this.key
      contexts[element.waypointContextKey] = this
      keyCounter += 1
  
      this.createThrottledScrollHandler()
      this.createThrottledResizeHandler()
    }
  
    /* Private */
    Context.prototype.add = function(waypoint) {
      var axis = waypoint.options.horizontal ? 'horizontal' : 'vertical'
      this.waypoints[axis][waypoint.key] = waypoint
      this.refresh()
    }
  
    /* Private */
    Context.prototype.checkEmpty = function() {
      var horizontalEmpty = this.Adapter.isEmptyObject(this.waypoints.horizontal)
      var verticalEmpty = this.Adapter.isEmptyObject(this.waypoints.vertical)
      if (horizontalEmpty && verticalEmpty) {
        this.adapter.off('.waypoints')
        delete contexts[this.key]
      }
    }
  
    /* Private */
    Context.prototype.createThrottledResizeHandler = function() {
      var self = this
  
      function resizeHandler() {
        self.handleResize()
        self.didResize = false
      }
  
      this.adapter.on('resize.waypoints', function() {
        if (!self.didResize) {
          self.didResize = true
          Waypoint.requestAnimationFrame(resizeHandler)
        }
      })
    }
  
    /* Private */
    Context.prototype.createThrottledScrollHandler = function() {
      var self = this
      function scrollHandler() {
        self.handleScroll()
        self.didScroll = false
      }
  
      this.adapter.on('scroll.waypoints', function() {
        if (!self.didScroll || Waypoint.isTouch) {
          self.didScroll = true
          Waypoint.requestAnimationFrame(scrollHandler)
        }
      })
    }
  
    /* Private */
    Context.prototype.handleResize = function() {
      Waypoint.Context.refreshAll()
    }
  
    /* Private */
    Context.prototype.handleScroll = function() {
      var triggeredGroups = {}
      var axes = {
        horizontal: {
          newScroll: this.adapter.scrollLeft(),
          oldScroll: this.oldScroll.x,
          forward: 'right',
          backward: 'left'
        },
        vertical: {
          newScroll: this.adapter.scrollTop(),
          oldScroll: this.oldScroll.y,
          forward: 'down',
          backward: 'up'
        }
      }
  
      for (var axisKey in axes) {
        var axis = axes[axisKey]
        var isForward = axis.newScroll > axis.oldScroll
        var direction = isForward ? axis.forward : axis.backward
  
        for (var waypointKey in this.waypoints[axisKey]) {
          var waypoint = this.waypoints[axisKey][waypointKey]
          var wasBeforeTriggerPoint = axis.oldScroll < waypoint.triggerPoint
          var nowAfterTriggerPoint = axis.newScroll >= waypoint.triggerPoint
          var crossedForward = wasBeforeTriggerPoint && nowAfterTriggerPoint
          var crossedBackward = !wasBeforeTriggerPoint && !nowAfterTriggerPoint
          if (crossedForward || crossedBackward) {
            waypoint.queueTrigger(direction)
            triggeredGroups[waypoint.group.id] = waypoint.group
          }
        }
      }
  
      for (var groupKey in triggeredGroups) {
        triggeredGroups[groupKey].flushTriggers()
      }
  
      this.oldScroll = {
        x: axes.horizontal.newScroll,
        y: axes.vertical.newScroll
      }
    }
  
    /* Private */
    Context.prototype.innerHeight = function() {
      /*eslint-disable eqeqeq */
      if (this.element == this.element.window) {
        return Waypoint.viewportHeight()
      }
      /*eslint-enable eqeqeq */
      return this.adapter.innerHeight()
    }
  
    /* Private */
    Context.prototype.remove = function(waypoint) {
      delete this.waypoints[waypoint.axis][waypoint.key]
      this.checkEmpty()
    }
  
    /* Private */
    Context.prototype.innerWidth = function() {
      /*eslint-disable eqeqeq */
      if (this.element == this.element.window) {
        return Waypoint.viewportWidth()
      }
      /*eslint-enable eqeqeq */
      return this.adapter.innerWidth()
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/context-destroy */
    Context.prototype.destroy = function() {
      var allWaypoints = []
      for (var axis in this.waypoints) {
        for (var waypointKey in this.waypoints[axis]) {
          allWaypoints.push(this.waypoints[axis][waypointKey])
        }
      }
      for (var i = 0, end = allWaypoints.length; i < end; i++) {
        allWaypoints[i].destroy()
      }
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/context-refresh */
    Context.prototype.refresh = function() {
      /*eslint-disable eqeqeq */
      var isWindow = this.element == this.element.window
      /*eslint-enable eqeqeq */
      var contextOffset = isWindow ? undefined : this.adapter.offset()
      var triggeredGroups = {}
      var axes
  
      this.handleScroll()
      axes = {
        horizontal: {
          contextOffset: isWindow ? 0 : contextOffset.left,
          contextScroll: isWindow ? 0 : this.oldScroll.x,
          contextDimension: this.innerWidth(),
          oldScroll: this.oldScroll.x,
          forward: 'right',
          backward: 'left',
          offsetProp: 'left'
        },
        vertical: {
          contextOffset: isWindow ? 0 : contextOffset.top,
          contextScroll: isWindow ? 0 : this.oldScroll.y,
          contextDimension: this.innerHeight(),
          oldScroll: this.oldScroll.y,
          forward: 'down',
          backward: 'up',
          offsetProp: 'top'
        }
      }
  
      for (var axisKey in axes) {
        var axis = axes[axisKey]
        for (var waypointKey in this.waypoints[axisKey]) {
          var waypoint = this.waypoints[axisKey][waypointKey]
          var adjustment = waypoint.options.offset
          var oldTriggerPoint = waypoint.triggerPoint
          var elementOffset = 0
          var freshWaypoint = oldTriggerPoint == null
          var contextModifier, wasBeforeScroll, nowAfterScroll
          var triggeredBackward, triggeredForward
  
          if (waypoint.element !== waypoint.element.window) {
            elementOffset = waypoint.adapter.offset()[axis.offsetProp]
          }
  
          if (typeof adjustment === 'function') {
            adjustment = adjustment.apply(waypoint)
          }
          else if (typeof adjustment === 'string') {
            adjustment = parseFloat(adjustment)
            if (waypoint.options.offset.indexOf('%') > - 1) {
              adjustment = Math.ceil(axis.contextDimension * adjustment / 100)
            }
          }
  
          contextModifier = axis.contextScroll - axis.contextOffset
          waypoint.triggerPoint = elementOffset + contextModifier - adjustment
          wasBeforeScroll = oldTriggerPoint < axis.oldScroll
          nowAfterScroll = waypoint.triggerPoint >= axis.oldScroll
          triggeredBackward = wasBeforeScroll && nowAfterScroll
          triggeredForward = !wasBeforeScroll && !nowAfterScroll
  
          if (!freshWaypoint && triggeredBackward) {
            waypoint.queueTrigger(axis.backward)
            triggeredGroups[waypoint.group.id] = waypoint.group
          }
          else if (!freshWaypoint && triggeredForward) {
            waypoint.queueTrigger(axis.forward)
            triggeredGroups[waypoint.group.id] = waypoint.group
          }
          else if (freshWaypoint && axis.oldScroll >= waypoint.triggerPoint) {
            waypoint.queueTrigger(axis.forward)
            triggeredGroups[waypoint.group.id] = waypoint.group
          }
        }
      }
  
      Waypoint.requestAnimationFrame(function() {
        for (var groupKey in triggeredGroups) {
          triggeredGroups[groupKey].flushTriggers()
        }
      })
  
      return this
    }
  
    /* Private */
    Context.findOrCreateByElement = function(element) {
      return Context.findByElement(element) || new Context(element)
    }
  
    /* Private */
    Context.refreshAll = function() {
      for (var contextId in contexts) {
        contexts[contextId].refresh()
      }
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/context-find-by-element */
    Context.findByElement = function(element) {
      return contexts[element.waypointContextKey]
    }
  
    window.onload = function() {
      if (oldWindowLoad) {
        oldWindowLoad()
      }
      Context.refreshAll()
    }
  
    Waypoint.requestAnimationFrame = function(callback) {
      var requestFn = window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        requestAnimationFrameShim
      requestFn.call(window, callback)
    }
    Waypoint.Context = Context
  }())
  ;(function() {
    'use strict'
  
    function byTriggerPoint(a, b) {
      return a.triggerPoint - b.triggerPoint
    }
  
    function byReverseTriggerPoint(a, b) {
      return b.triggerPoint - a.triggerPoint
    }
  
    var groups = {
      vertical: {},
      horizontal: {}
    }
    var Waypoint = window.Waypoint
  
    /* http://imakewebthings.com/waypoints/api/group */
    function Group(options) {
      this.name = options.name
      this.axis = options.axis
      this.id = this.name + '-' + this.axis
      this.waypoints = []
      this.clearTriggerQueues()
      groups[this.axis][this.name] = this
    }
  
    /* Private */
    Group.prototype.add = function(waypoint) {
      this.waypoints.push(waypoint)
    }
  
    /* Private */
    Group.prototype.clearTriggerQueues = function() {
      this.triggerQueues = {
        up: [],
        down: [],
        left: [],
        right: []
      }
    }
  
    /* Private */
    Group.prototype.flushTriggers = function() {
      for (var direction in this.triggerQueues) {
        var waypoints = this.triggerQueues[direction]
        var reverse = direction === 'up' || direction === 'left'
        waypoints.sort(reverse ? byReverseTriggerPoint : byTriggerPoint)
        for (var i = 0, end = waypoints.length; i < end; i += 1) {
          var waypoint = waypoints[i]
          if (waypoint.options.continuous || i === waypoints.length - 1) {
            waypoint.trigger([direction])
          }
        }
      }
      this.clearTriggerQueues()
    }
  
    /* Private */
    Group.prototype.next = function(waypoint) {
      this.waypoints.sort(byTriggerPoint)
      var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
      var isLast = index === this.waypoints.length - 1
      return isLast ? null : this.waypoints[index + 1]
    }
  
    /* Private */
    Group.prototype.previous = function(waypoint) {
      this.waypoints.sort(byTriggerPoint)
      var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
      return index ? this.waypoints[index - 1] : null
    }
  
    /* Private */
    Group.prototype.queueTrigger = function(waypoint, direction) {
      this.triggerQueues[direction].push(waypoint)
    }
  
    /* Private */
    Group.prototype.remove = function(waypoint) {
      var index = Waypoint.Adapter.inArray(waypoint, this.waypoints)
      if (index > -1) {
        this.waypoints.splice(index, 1)
      }
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/first */
    Group.prototype.first = function() {
      return this.waypoints[0]
    }
  
    /* Public */
    /* http://imakewebthings.com/waypoints/api/last */
    Group.prototype.last = function() {
      return this.waypoints[this.waypoints.length - 1]
    }
  
    /* Private */
    Group.findOrCreate = function(options) {
      return groups[options.axis][options.name] || new Group(options)
    }
  
    Waypoint.Group = Group
  }())
  ;(function() {
    'use strict'
  
    var $ = window.jQuery
    var Waypoint = window.Waypoint
  
    function JQueryAdapter(element) {
      this.$element = $(element)
    }
  
    $.each([
      'innerHeight',
      'innerWidth',
      'off',
      'offset',
      'on',
      'outerHeight',
      'outerWidth',
      'scrollLeft',
      'scrollTop'
    ], function(i, method) {
      JQueryAdapter.prototype[method] = function() {
        var args = Array.prototype.slice.call(arguments)
        return this.$element[method].apply(this.$element, args)
      }
    })
  
    $.each([
      'extend',
      'inArray',
      'isEmptyObject'
    ], function(i, method) {
      JQueryAdapter[method] = $[method]
    })
  
    Waypoint.adapters.push({
      name: 'jquery',
      Adapter: JQueryAdapter
    })
    Waypoint.Adapter = JQueryAdapter
  }())
  ;(function() {
    'use strict'
  
    var Waypoint = window.Waypoint
  
    function createExtension(framework) {
      return function() {
        var waypoints = []
        var overrides = arguments[0]
  
        if (framework.isFunction(arguments[0])) {
          overrides = framework.extend({}, arguments[1])
          overrides.handler = arguments[0]
        }
  
        this.each(function() {
          var options = framework.extend({}, overrides, {
            element: this
          })
          if (typeof options.context === 'string') {
            options.context = framework(this).closest(options.context)[0]
          }
          waypoints.push(new Waypoint(options))
        })
  
        return waypoints
      }
    }
  
    if (window.jQuery) {
      window.jQuery.fn.waypoint = createExtension(window.jQuery)
    }
    if (window.Zepto) {
      window.Zepto.fn.waypoint = createExtension(window.Zepto)
    }
  }())
  ;
  /**
   *
   * Version: 0.0.6
   * Author: Gianluca Guarini
   * Contact: gianluca.guarini@gmail.com
   * Website: http://www.gianlucaguarini.com/
   * Twitter: @gianlucaguarini
   *
   * Copyright (c) Gianluca Guarini
   *
   * Permission is hereby granted, free of charge, to any person
   * obtaining a copy of this software and associated documentation
   * files (the "Software"), to deal in the Software without
   * restriction, including without limitation the rights to use,
   * copy, modify, merge, publish, distribute, sublicense, and/or sell
   * copies of the Software, and to permit persons to whom the
   * Software is furnished to do so, subject to the following
   * conditions:
   *
   * The above copyright notice and this permission notice shall be
   * included in all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
   * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
   * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
   * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
   * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
   * OTHER DEALINGS IN THE SOFTWARE.
   **/
  
  
  (function(window, document, $) {
    'use strict';
  
    // Plugin private cache
    // static vars
    var cache = {
      filterId: 0
    },
      $body = $('body');
  
    var Vague = function(elm, customOptions) {
      // Default options
      var defaultOptions = {
        intensity: 5,
        forceSVGUrl: false,
        animationOptions: {
          duration: 1000,
          easing: 'linear'
        }
      },
        // extend the default options with the ones passed to the plugin
        options = $.extend(defaultOptions, customOptions),
  
        /*
         *
         * Helpers
         *
         */
  
        _browserPrefixes = ' -webkit- -moz- -o- -ms- '.split(' '),
        _cssPrefixString = {},
        _cssPrefix = function(property) {
          if (_cssPrefixString[property] || _cssPrefixString[property] === '') return _cssPrefixString[property] + property;
          var e = document.createElement('div');
          var prefixes = ['', 'Moz', 'Webkit', 'O', 'ms', 'Khtml']; // Various supports...
          for (var i in prefixes) {
            if (typeof e.style[prefixes[i] + property] !== 'undefined') {
              _cssPrefixString[property] = prefixes[i];
              return prefixes[i] + property;
            }
          }
          return property.toLowerCase();
        },
        // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/css-filters.js
        _support = {
          cssfilters: function() {
            var el = document.createElement('div');
            el.style.cssText = _browserPrefixes.join('filter' + ':blur(2px); ');
            return !!el.style.length && ((document.documentMode === undefined || document.documentMode > 9));
          }(),
  
          // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/svg-filters.js
          svgfilters: function() {
            var result = false;
            try {
              result = typeof SVGFEColorMatrixElement !== undefined &&
                SVGFEColorMatrixElement.SVG_FECOLORMATRIX_TYPE_SATURATE == 2;
            } catch (e) {}
            return result;
          }()
        },
  
        /*
         *
         * PRIVATE VARS
         *
         */
  
        _blurred = false,
        // cache the right prefixed css filter property
        _cssFilterProp = _cssPrefix('Filter'),
        _svgGaussianFilter,
        _filterId,
        // to cache the jquery animation instance
        _animation,
  
        /*
         *
         * PRIVATE METHODS
         *
         */
  
        /**
         * Create any svg element
         * @param  { String } tagName: svg tag name
         * @return { SVG Node }
         */
  
        _createSvgElement = function(tagName) {
          return document.createElementNS('http://www.w3.org/2000/svg', tagName);
        },
  
        /**
         *
         * Inject the svg tag into the DOM
         * we will use it only if the css filters are not supported
         *
         */
  
        _appendSVGFilter = function() {
          // create the svg and the filter tags
          var svg = _createSvgElement('svg'),
            filter = _createSvgElement('filter');
  
          // cache the feGaussianBlur tag and make it available
          // outside of this function to easily update the blur intensity
          _svgGaussianFilter = _createSvgElement('feGaussianBlur');
  
          // hide the svg tag
          // we don't want to see it into the DOM!
          svg.setAttribute('style', 'position:absolute');
          svg.setAttribute('width', '0');
          svg.setAttribute('height', '0');
          // set the id that will be used as link between the DOM element to blur and the svg just created
          filter.setAttribute('id', 'blur-effect-id-' + cache.filterId);
  
          filter.appendChild(_svgGaussianFilter);
          svg.appendChild(filter);
          // append the svg into the body
          $body.append(svg);
  
        };
  
      /*
       *
       * PUBLIC VARS
       *
       */
  
      // cache the DOM element to blur
      this.$elm = elm instanceof $ ? elm : $(elm);
  
  
      /*
       *
       * PUBLIC METHODS
       *
       */
  
      /**
       *
       * Initialize the plugin creating a new svg if necessary
       *
       */
  
      this.init = function() {
        // checking the css filter feature
        if (_support.svgfilters) {
          _appendSVGFilter();
        }
        // cache the filter id
        _filterId = cache.filterId;
        // increment the filter id static var
        cache.filterId++;
  
        return this;
  
      };
  
      /**
       *
       * Blur the DOM element selected
       *
       */
  
      this.blur = function() {
  
        var cssFilterValue,
          // variables needed to force the svg filter URL
          loc = window.location,
          svgUrl = options.forceSVGUrl ? loc.protocol + '//' + loc.host + loc.pathname + loc.search : '';
  
        // use the css filters if supported
        if (_support.cssfilters) {
          cssFilterValue = 'blur(' + options.intensity + 'px)';
          // .. or use the svg filters
        } else if (_support.svgfilters) {
          // update the svg stdDeviation tag to set up the blur intensity
          _svgGaussianFilter.setAttribute('stdDeviation', options.intensity);
          cssFilterValue = 'url(' + svgUrl + '#blur-effect-id-' + _filterId + ')';
        } else {
          // .. use the IE css filters
          cssFilterValue = 'progid:DXImageTransform.Microsoft.Blur(pixelradius=' + options.intensity + ')';
        }
  
        // update the DOM element css
        this.$elm[0].style[_cssFilterProp] = cssFilterValue;
        // set the _blurred internal var to true to cache the element current status
        _blurred = true;
  
        return this;
      };
  
  
      /**
       * Animate the blur intensity
       * @param  { Int } newIntensity: new blur intensity value
       * @param  { Object } customAnimationOptions: default jQuery animate options
       */
  
      this.animate = function(newIntensity, customAnimationOptions) {
        // control the new blur intensity checking if it's a valid value
        if (typeof newIntensity !== 'number') {
          throw (typeof newIntensity + ' is not a valid number to animate the blur');
        } else if (newIntensity < 0) {
          throw ('I can animate only positive numbers');
        }
        // create a new jQuery deferred instance
        var dfr = new $.Deferred();
  
        // kill the previous animation
        if (_animation) {
          _animation.stop(true, true);
        }
  
        // trigger the animation using the jQuery Animation class
        _animation = new $.Animation(options, {
          intensity: newIntensity
        }, $.extend(options.animationOptions, customAnimationOptions))
          .progress($.proxy(this.blur, this))
          .done(dfr.resolve);
  
        // return the animation deferred promise
        return dfr.promise();
      };
  
      /**
       *
       * Unblur the DOM element
       *
       */
      this.unblur = function() {
        // set the DOM filter property to none
        this.$elm.css(_cssFilterProp, 'none');
        _blurred = false;
        return this;
      };
  
      /**
       *
       * Trigger alternatively the @blur and @unblur methods
       *
       */
  
      this.toggleblur = function() {
        if (_blurred) {
          this.unblur();
        } else {
          this.blur();
        }
        return this;
      };
      /**
       * Destroy the Vague.js instance removing also the svg filter injected into the DOM
       */
      this.destroy = function() {
        // do we need to remove the svg filter?
        if (_support.svgfilters) {
          $('filter#blur-effect-id-' + _filterId).parent().remove();
        }
  
        this.unblur();
  
        // clear all the property stored into this Vague.js instance
        for (var prop in this) {
          delete this[prop];
        }
  
        return this;
      };
      // init the plugin
      return this.init();
    };
  
    // export the plugin as a jQuery function
    $.fn.Vague = function(options) {
      return new Vague(this, options);
    };
  
  }(window, document, jQuery));
  
  /** vim: et:ts=4:sw=4:sts=4
   * @license RequireJS 2.3.5 Copyright jQuery Foundation and other contributors.
   * Released under MIT license, https://github.com/requirejs/requirejs/blob/master/LICENSE
   */
  //Not using strict: uneven strict support in browsers, #392, and causes
  //problems with requirejs.exec()/transpiler plugins that may not be strict.
  /*jslint regexp: true, nomen: true, sloppy: true */
  /*global window, navigator, document, importScripts, setTimeout, opera */
  
  var requirejs, require, define;
  (function (global, setTimeout) {
      var req, s, head, baseElement, dataMain, src,
          interactiveScript, currentlyAddingScript, mainScript, subPath,
          version = '2.3.5',
          commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/mg,
          cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
          jsSuffixRegExp = /\.js$/,
          currDirRegExp = /^\.\//,
          op = Object.prototype,
          ostring = op.toString,
          hasOwn = op.hasOwnProperty,
          isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document),
          isWebWorker = !isBrowser && typeof importScripts !== 'undefined',
          //PS3 indicates loaded and complete, but need to wait for complete
          //specifically. Sequence is 'loading', 'loaded', execution,
          // then 'complete'. The UA check is unfortunate, but not sure how
          //to feature test w/o causing perf issues.
          readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ?
                        /^complete$/ : /^(complete|loaded)$/,
          defContextName = '_',
          //Oh the tragedy, detecting opera. See the usage of isOpera for reason.
          isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]',
          contexts = {},
          cfg = {},
          globalDefQueue = [],
          useInteractive = false;
  
      //Could match something like ')//comment', do not lose the prefix to comment.
      function commentReplace(match, singlePrefix) {
          return singlePrefix || '';
      }
  
      function isFunction(it) {
          return ostring.call(it) === '[object Function]';
      }
  
      function isArray(it) {
          return ostring.call(it) === '[object Array]';
      }
  
      /**
       * Helper function for iterating over an array. If the func returns
       * a true value, it will break out of the loop.
       */
      function each(ary, func) {
          if (ary) {
              var i;
              for (i = 0; i < ary.length; i += 1) {
                  if (ary[i] && func(ary[i], i, ary)) {
                      break;
                  }
              }
          }
      }
  
      /**
       * Helper function for iterating over an array backwards. If the func
       * returns a true value, it will break out of the loop.
       */
      function eachReverse(ary, func) {
          if (ary) {
              var i;
              for (i = ary.length - 1; i > -1; i -= 1) {
                  if (ary[i] && func(ary[i], i, ary)) {
                      break;
                  }
              }
          }
      }
  
      function hasProp(obj, prop) {
          return hasOwn.call(obj, prop);
      }
  
      function getOwn(obj, prop) {
          return hasProp(obj, prop) && obj[prop];
      }
  
      /**
       * Cycles over properties in an object and calls a function for each
       * property value. If the function returns a truthy value, then the
       * iteration is stopped.
       */
      function eachProp(obj, func) {
          var prop;
          for (prop in obj) {
              if (hasProp(obj, prop)) {
                  if (func(obj[prop], prop)) {
                      break;
                  }
              }
          }
      }
  
      /**
       * Simple function to mix in properties from source into target,
       * but only if target does not already have a property of the same name.
       */
      function mixin(target, source, force, deepStringMixin) {
          if (source) {
              eachProp(source, function (value, prop) {
                  if (force || !hasProp(target, prop)) {
                      if (deepStringMixin && typeof value === 'object' && value &&
                          !isArray(value) && !isFunction(value) &&
                          !(value instanceof RegExp)) {
  
                          if (!target[prop]) {
                              target[prop] = {};
                          }
                          mixin(target[prop], value, force, deepStringMixin);
                      } else {
                          target[prop] = value;
                      }
                  }
              });
          }
          return target;
      }
  
      //Similar to Function.prototype.bind, but the 'this' object is specified
      //first, since it is easier to read/figure out what 'this' will be.
      function bind(obj, fn) {
          return function () {
              return fn.apply(obj, arguments);
          };
      }
  
      function scripts() {
          return document.getElementsByTagName('script');
      }
  
      function defaultOnError(err) {
          throw err;
      }
  
      //Allow getting a global that is expressed in
      //dot notation, like 'a.b.c'.
      function getGlobal(value) {
          if (!value) {
              return value;
          }
          var g = global;
          each(value.split('.'), function (part) {
              g = g[part];
          });
          return g;
      }
  
      /**
       * Constructs an error with a pointer to an URL with more information.
       * @param {String} id the error ID that maps to an ID on a web page.
       * @param {String} message human readable error.
       * @param {Error} [err] the original error, if there is one.
       *
       * @returns {Error}
       */
      function makeError(id, msg, err, requireModules) {
          var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id);
          e.requireType = id;
          e.requireModules = requireModules;
          if (err) {
              e.originalError = err;
          }
          return e;
      }
  
      if (typeof define !== 'undefined') {
          //If a define is already in play via another AMD loader,
          //do not overwrite.
          return;
      }
  
      if (typeof requirejs !== 'undefined') {
          if (isFunction(requirejs)) {
              //Do not overwrite an existing requirejs instance.
              return;
          }
          cfg = requirejs;
          requirejs = undefined;
      }
  
      //Allow for a require config object
      if (typeof require !== 'undefined' && !isFunction(require)) {
          //assume it is a config object.
          cfg = require;
          require = undefined;
      }
  
      function newContext(contextName) {
          var inCheckLoaded, Module, context, handlers,
              checkLoadedTimeoutId,
              config = {
                  //Defaults. Do not set a default for map
                  //config to speed up normalize(), which
                  //will run faster if there is no default.
                  waitSeconds: 7,
                  baseUrl: './',
                  paths: {},
                  bundles: {},
                  pkgs: {},
                  shim: {},
                  config: {}
              },
              registry = {},
              //registry of just enabled modules, to speed
              //cycle breaking code when lots of modules
              //are registered, but not activated.
              enabledRegistry = {},
              undefEvents = {},
              defQueue = [],
              defined = {},
              urlFetched = {},
              bundlesMap = {},
              requireCounter = 1,
              unnormalizedCounter = 1;
  
          /**
           * Trims the . and .. from an array of path segments.
           * It will keep a leading path segment if a .. will become
           * the first path segment, to help with module name lookups,
           * which act like paths, but can be remapped. But the end result,
           * all paths that use this function should look normalized.
           * NOTE: this method MODIFIES the input array.
           * @param {Array} ary the array of path segments.
           */
          function trimDots(ary) {
              var i, part;
              for (i = 0; i < ary.length; i++) {
                  part = ary[i];
                  if (part === '.') {
                      ary.splice(i, 1);
                      i -= 1;
                  } else if (part === '..') {
                      // If at the start, or previous value is still ..,
                      // keep them so that when converted to a path it may
                      // still work when converted to a path, even though
                      // as an ID it is less than ideal. In larger point
                      // releases, may be better to just kick out an error.
                      if (i === 0 || (i === 1 && ary[2] === '..') || ary[i - 1] === '..') {
                          continue;
                      } else if (i > 0) {
                          ary.splice(i - 1, 2);
                          i -= 2;
                      }
                  }
              }
          }
  
          /**
           * Given a relative module name, like ./something, normalize it to
           * a real name that can be mapped to a path.
           * @param {String} name the relative name
           * @param {String} baseName a real name that the name arg is relative
           * to.
           * @param {Boolean} applyMap apply the map config to the value. Should
           * only be done if this normalization is for a dependency ID.
           * @returns {String} normalized name
           */
          function normalize(name, baseName, applyMap) {
              var pkgMain, mapValue, nameParts, i, j, nameSegment, lastIndex,
                  foundMap, foundI, foundStarMap, starI, normalizedBaseParts,
                  baseParts = (baseName && baseName.split('/')),
                  map = config.map,
                  starMap = map && map['*'];
  
              //Adjust any relative paths.
              if (name) {
                  name = name.split('/');
                  lastIndex = name.length - 1;
  
                  // If wanting node ID compatibility, strip .js from end
                  // of IDs. Have to do this here, and not in nameToUrl
                  // because node allows either .js or non .js to map
                  // to same file.
                  if (config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex])) {
                      name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, '');
                  }
  
                  // Starts with a '.' so need the baseName
                  if (name[0].charAt(0) === '.' && baseParts) {
                      //Convert baseName to array, and lop off the last part,
                      //so that . matches that 'directory' and not name of the baseName's
                      //module. For instance, baseName of 'one/two/three', maps to
                      //'one/two/three.js', but we want the directory, 'one/two' for
                      //this normalization.
                      normalizedBaseParts = baseParts.slice(0, baseParts.length - 1);
                      name = normalizedBaseParts.concat(name);
                  }
  
                  trimDots(name);
                  name = name.join('/');
              }
  
              //Apply map config if available.
              if (applyMap && map && (baseParts || starMap)) {
                  nameParts = name.split('/');
  
                  outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
                      nameSegment = nameParts.slice(0, i).join('/');
  
                      if (baseParts) {
                          //Find the longest baseName segment match in the config.
                          //So, do joins on the biggest to smallest lengths of baseParts.
                          for (j = baseParts.length; j > 0; j -= 1) {
                              mapValue = getOwn(map, baseParts.slice(0, j).join('/'));
  
                              //baseName segment has config, find if it has one for
                              //this name.
                              if (mapValue) {
                                  mapValue = getOwn(mapValue, nameSegment);
                                  if (mapValue) {
                                      //Match, update name to the new value.
                                      foundMap = mapValue;
                                      foundI = i;
                                      break outerLoop;
                                  }
                              }
                          }
                      }
  
                      //Check for a star map match, but just hold on to it,
                      //if there is a shorter segment match later in a matching
                      //config, then favor over this star map.
                      if (!foundStarMap && starMap && getOwn(starMap, nameSegment)) {
                          foundStarMap = getOwn(starMap, nameSegment);
                          starI = i;
                      }
                  }
  
                  if (!foundMap && foundStarMap) {
                      foundMap = foundStarMap;
                      foundI = starI;
                  }
  
                  if (foundMap) {
                      nameParts.splice(0, foundI, foundMap);
                      name = nameParts.join('/');
                  }
              }
  
              // If the name points to a package's name, use
              // the package main instead.
              pkgMain = getOwn(config.pkgs, name);
  
              return pkgMain ? pkgMain : name;
          }
  
          function removeScript(name) {
              if (isBrowser) {
                  each(scripts(), function (scriptNode) {
                      if (scriptNode.getAttribute('data-requiremodule') === name &&
                              scriptNode.getAttribute('data-requirecontext') === context.contextName) {
                          scriptNode.parentNode.removeChild(scriptNode);
                          return true;
                      }
                  });
              }
          }
  
          function hasPathFallback(id) {
              var pathConfig = getOwn(config.paths, id);
              if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) {
                  //Pop off the first array value, since it failed, and
                  //retry
                  pathConfig.shift();
                  context.require.undef(id);
  
                  //Custom require that does not do map translation, since
                  //ID is "absolute", already mapped/resolved.
                  context.makeRequire(null, {
                      skipMap: true
                  })([id]);
  
                  return true;
              }
          }
  
          //Turns a plugin!resource to [plugin, resource]
          //with the plugin being undefined if the name
          //did not have a plugin prefix.
          function splitPrefix(name) {
              var prefix,
                  index = name ? name.indexOf('!') : -1;
              if (index > -1) {
                  prefix = name.substring(0, index);
                  name = name.substring(index + 1, name.length);
              }
              return [prefix, name];
          }
  
          /**
           * Creates a module mapping that includes plugin prefix, module
           * name, and path. If parentModuleMap is provided it will
           * also normalize the name via require.normalize()
           *
           * @param {String} name the module name
           * @param {String} [parentModuleMap] parent module map
           * for the module name, used to resolve relative names.
           * @param {Boolean} isNormalized: is the ID already normalized.
           * This is true if this call is done for a define() module ID.
           * @param {Boolean} applyMap: apply the map config to the ID.
           * Should only be true if this map is for a dependency.
           *
           * @returns {Object}
           */
          function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
              var url, pluginModule, suffix, nameParts,
                  prefix = null,
                  parentName = parentModuleMap ? parentModuleMap.name : null,
                  originalName = name,
                  isDefine = true,
                  normalizedName = '';
  
              //If no name, then it means it is a require call, generate an
              //internal name.
              if (!name) {
                  isDefine = false;
                  name = '_@r' + (requireCounter += 1);
              }
  
              nameParts = splitPrefix(name);
              prefix = nameParts[0];
              name = nameParts[1];
  
              if (prefix) {
                  prefix = normalize(prefix, parentName, applyMap);
                  pluginModule = getOwn(defined, prefix);
              }
  
              //Account for relative paths if there is a base name.
              if (name) {
                  if (prefix) {
                      if (isNormalized) {
                          normalizedName = name;
                      } else if (pluginModule && pluginModule.normalize) {
                          //Plugin is loaded, use its normalize method.
                          normalizedName = pluginModule.normalize(name, function (name) {
                              return normalize(name, parentName, applyMap);
                          });
                      } else {
                          // If nested plugin references, then do not try to
                          // normalize, as it will not normalize correctly. This
                          // places a restriction on resourceIds, and the longer
                          // term solution is not to normalize until plugins are
                          // loaded and all normalizations to allow for async
                          // loading of a loader plugin. But for now, fixes the
                          // common uses. Details in #1131
                          normalizedName = name.indexOf('!') === -1 ?
                                           normalize(name, parentName, applyMap) :
                                           name;
                      }
                  } else {
                      //A regular module.
                      normalizedName = normalize(name, parentName, applyMap);
  
                      //Normalized name may be a plugin ID due to map config
                      //application in normalize. The map config values must
                      //already be normalized, so do not need to redo that part.
                      nameParts = splitPrefix(normalizedName);
                      prefix = nameParts[0];
                      normalizedName = nameParts[1];
                      isNormalized = true;
  
                      url = context.nameToUrl(normalizedName);
                  }
              }
  
              //If the id is a plugin id that cannot be determined if it needs
              //normalization, stamp it with a unique ID so two matching relative
              //ids that may conflict can be separate.
              suffix = prefix && !pluginModule && !isNormalized ?
                       '_unnormalized' + (unnormalizedCounter += 1) :
                       '';
  
              return {
                  prefix: prefix,
                  name: normalizedName,
                  parentMap: parentModuleMap,
                  unnormalized: !!suffix,
                  url: url,
                  originalName: originalName,
                  isDefine: isDefine,
                  id: (prefix ?
                          prefix + '!' + normalizedName :
                          normalizedName) + suffix
              };
          }
  
          function getModule(depMap) {
              var id = depMap.id,
                  mod = getOwn(registry, id);
  
              if (!mod) {
                  mod = registry[id] = new context.Module(depMap);
              }
  
              return mod;
          }
  
          function on(depMap, name, fn) {
              var id = depMap.id,
                  mod = getOwn(registry, id);
  
              if (hasProp(defined, id) &&
                      (!mod || mod.defineEmitComplete)) {
                  if (name === 'defined') {
                      fn(defined[id]);
                  }
              } else {
                  mod = getModule(depMap);
                  if (mod.error && name === 'error') {
                      fn(mod.error);
                  } else {
                      mod.on(name, fn);
                  }
              }
          }
  
          function onError(err, errback) {
              var ids = err.requireModules,
                  notified = false;
  
              if (errback) {
                  errback(err);
              } else {
                  each(ids, function (id) {
                      var mod = getOwn(registry, id);
                      if (mod) {
                          //Set error on module, so it skips timeout checks.
                          mod.error = err;
                          if (mod.events.error) {
                              notified = true;
                              mod.emit('error', err);
                          }
                      }
                  });
  
                  if (!notified) {
                      req.onError(err);
                  }
              }
          }
  
          /**
           * Internal method to transfer globalQueue items to this context's
           * defQueue.
           */
          function takeGlobalQueue() {
              //Push all the globalDefQueue items into the context's defQueue
              if (globalDefQueue.length) {
                  each(globalDefQueue, function(queueItem) {
                      var id = queueItem[0];
                      if (typeof id === 'string') {
                          context.defQueueMap[id] = true;
                      }
                      defQueue.push(queueItem);
                  });
                  globalDefQueue = [];
              }
          }
  
          handlers = {
              'require': function (mod) {
                  if (mod.require) {
                      return mod.require;
                  } else {
                      return (mod.require = context.makeRequire(mod.map));
                  }
              },
              'exports': function (mod) {
                  mod.usingExports = true;
                  if (mod.map.isDefine) {
                      if (mod.exports) {
                          return (defined[mod.map.id] = mod.exports);
                      } else {
                          return (mod.exports = defined[mod.map.id] = {});
                      }
                  }
              },
              'module': function (mod) {
                  if (mod.module) {
                      return mod.module;
                  } else {
                      return (mod.module = {
                          id: mod.map.id,
                          uri: mod.map.url,
                          config: function () {
                              return getOwn(config.config, mod.map.id) || {};
                          },
                          exports: mod.exports || (mod.exports = {})
                      });
                  }
              }
          };
  
          function cleanRegistry(id) {
              //Clean up machinery used for waiting modules.
              delete registry[id];
              delete enabledRegistry[id];
          }
  
          function breakCycle(mod, traced, processed) {
              var id = mod.map.id;
  
              if (mod.error) {
                  mod.emit('error', mod.error);
              } else {
                  traced[id] = true;
                  each(mod.depMaps, function (depMap, i) {
                      var depId = depMap.id,
                          dep = getOwn(registry, depId);
  
                      //Only force things that have not completed
                      //being defined, so still in the registry,
                      //and only if it has not been matched up
                      //in the module already.
                      if (dep && !mod.depMatched[i] && !processed[depId]) {
                          if (getOwn(traced, depId)) {
                              mod.defineDep(i, defined[depId]);
                              mod.check(); //pass false?
                          } else {
                              breakCycle(dep, traced, processed);
                          }
                      }
                  });
                  processed[id] = true;
              }
          }
  
          function checkLoaded() {
              var err, usingPathFallback,
                  waitInterval = config.waitSeconds * 1000,
                  //It is possible to disable the wait interval by using waitSeconds of 0.
                  expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(),
                  noLoads = [],
                  reqCalls = [],
                  stillLoading = false,
                  needCycleCheck = true;
  
              //Do not bother if this call was a result of a cycle break.
              if (inCheckLoaded) {
                  return;
              }
  
              inCheckLoaded = true;
  
              //Figure out the state of all the modules.
              eachProp(enabledRegistry, function (mod) {
                  var map = mod.map,
                      modId = map.id;
  
                  //Skip things that are not enabled or in error state.
                  if (!mod.enabled) {
                      return;
                  }
  
                  if (!map.isDefine) {
                      reqCalls.push(mod);
                  }
  
                  if (!mod.error) {
                      //If the module should be executed, and it has not
                      //been inited and time is up, remember it.
                      if (!mod.inited && expired) {
                          if (hasPathFallback(modId)) {
                              usingPathFallback = true;
                              stillLoading = true;
                          } else {
                              noLoads.push(modId);
                              removeScript(modId);
                          }
                      } else if (!mod.inited && mod.fetched && map.isDefine) {
                          stillLoading = true;
                          if (!map.prefix) {
                              //No reason to keep looking for unfinished
                              //loading. If the only stillLoading is a
                              //plugin resource though, keep going,
                              //because it may be that a plugin resource
                              //is waiting on a non-plugin cycle.
                              return (needCycleCheck = false);
                          }
                      }
                  }
              });
  
              if (expired && noLoads.length) {
                  //If wait time expired, throw error of unloaded modules.
                  err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads);
                  err.contextName = context.contextName;
                  return onError(err);
              }
  
              //Not expired, check for a cycle.
              if (needCycleCheck) {
                  each(reqCalls, function (mod) {
                      breakCycle(mod, {}, {});
                  });
              }
  
              //If still waiting on loads, and the waiting load is something
              //other than a plugin resource, or there are still outstanding
              //scripts, then just try back later.
              if ((!expired || usingPathFallback) && stillLoading) {
                  //Something is still waiting to load. Wait for it, but only
                  //if a timeout is not already in effect.
                  if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) {
                      checkLoadedTimeoutId = setTimeout(function () {
                          checkLoadedTimeoutId = 0;
                          checkLoaded();
                      }, 50);
                  }
              }
  
              inCheckLoaded = false;
          }
  
          Module = function (map) {
              this.events = getOwn(undefEvents, map.id) || {};
              this.map = map;
              this.shim = getOwn(config.shim, map.id);
              this.depExports = [];
              this.depMaps = [];
              this.depMatched = [];
              this.pluginMaps = {};
              this.depCount = 0;
  
              /* this.exports this.factory
                 this.depMaps = [],
                 this.enabled, this.fetched
              */
          };
  
          Module.prototype = {
              init: function (depMaps, factory, errback, options) {
                  options = options || {};
  
                  //Do not do more inits if already done. Can happen if there
                  //are multiple define calls for the same module. That is not
                  //a normal, common case, but it is also not unexpected.
                  if (this.inited) {
                      return;
                  }
  
                  this.factory = factory;
  
                  if (errback) {
                      //Register for errors on this module.
                      this.on('error', errback);
                  } else if (this.events.error) {
                      //If no errback already, but there are error listeners
                      //on this module, set up an errback to pass to the deps.
                      errback = bind(this, function (err) {
                          this.emit('error', err);
                      });
                  }
  
                  //Do a copy of the dependency array, so that
                  //source inputs are not modified. For example
                  //"shim" deps are passed in here directly, and
                  //doing a direct modification of the depMaps array
                  //would affect that config.
                  this.depMaps = depMaps && depMaps.slice(0);
  
                  this.errback = errback;
  
                  //Indicate this module has be initialized
                  this.inited = true;
  
                  this.ignore = options.ignore;
  
                  //Could have option to init this module in enabled mode,
                  //or could have been previously marked as enabled. However,
                  //the dependencies are not known until init is called. So
                  //if enabled previously, now trigger dependencies as enabled.
                  if (options.enabled || this.enabled) {
                      //Enable this module and dependencies.
                      //Will call this.check()
                      this.enable();
                  } else {
                      this.check();
                  }
              },
  
              defineDep: function (i, depExports) {
                  //Because of cycles, defined callback for a given
                  //export can be called more than once.
                  if (!this.depMatched[i]) {
                      this.depMatched[i] = true;
                      this.depCount -= 1;
                      this.depExports[i] = depExports;
                  }
              },
  
              fetch: function () {
                  if (this.fetched) {
                      return;
                  }
                  this.fetched = true;
  
                  context.startTime = (new Date()).getTime();
  
                  var map = this.map;
  
                  //If the manager is for a plugin managed resource,
                  //ask the plugin to load it now.
                  if (this.shim) {
                      context.makeRequire(this.map, {
                          enableBuildCallback: true
                      })(this.shim.deps || [], bind(this, function () {
                          return map.prefix ? this.callPlugin() : this.load();
                      }));
                  } else {
                      //Regular dependency.
                      return map.prefix ? this.callPlugin() : this.load();
                  }
              },
  
              load: function () {
                  var url = this.map.url;
  
                  //Regular dependency.
                  if (!urlFetched[url]) {
                      urlFetched[url] = true;
                      context.load(this.map.id, url);
                  }
              },
  
              /**
               * Checks if the module is ready to define itself, and if so,
               * define it.
               */
              check: function () {
                  if (!this.enabled || this.enabling) {
                      return;
                  }
  
                  var err, cjsModule,
                      id = this.map.id,
                      depExports = this.depExports,
                      exports = this.exports,
                      factory = this.factory;
  
                  if (!this.inited) {
                      // Only fetch if not already in the defQueue.
                      if (!hasProp(context.defQueueMap, id)) {
                          this.fetch();
                      }
                  } else if (this.error) {
                      this.emit('error', this.error);
                  } else if (!this.defining) {
                      //The factory could trigger another require call
                      //that would result in checking this module to
                      //define itself again. If already in the process
                      //of doing that, skip this work.
                      this.defining = true;
  
                      if (this.depCount < 1 && !this.defined) {
                          if (isFunction(factory)) {
                              //If there is an error listener, favor passing
                              //to that instead of throwing an error. However,
                              //only do it for define()'d  modules. require
                              //errbacks should not be called for failures in
                              //their callbacks (#699). However if a global
                              //onError is set, use that.
                              if ((this.events.error && this.map.isDefine) ||
                                  req.onError !== defaultOnError) {
                                  try {
                                      exports = context.execCb(id, factory, depExports, exports);
                                  } catch (e) {
                                      err = e;
                                  }
                              } else {
                                  exports = context.execCb(id, factory, depExports, exports);
                              }
  
                              // Favor return value over exports. If node/cjs in play,
                              // then will not have a return value anyway. Favor
                              // module.exports assignment over exports object.
                              if (this.map.isDefine && exports === undefined) {
                                  cjsModule = this.module;
                                  if (cjsModule) {
                                      exports = cjsModule.exports;
                                  } else if (this.usingExports) {
                                      //exports already set the defined value.
                                      exports = this.exports;
                                  }
                              }
  
                              if (err) {
                                  err.requireMap = this.map;
                                  err.requireModules = this.map.isDefine ? [this.map.id] : null;
                                  err.requireType = this.map.isDefine ? 'define' : 'require';
                                  return onError((this.error = err));
                              }
  
                          } else {
                              //Just a literal value
                              exports = factory;
                          }
  
                          this.exports = exports;
  
                          if (this.map.isDefine && !this.ignore) {
                              defined[id] = exports;
  
                              if (req.onResourceLoad) {
                                  var resLoadMaps = [];
                                  each(this.depMaps, function (depMap) {
                                      resLoadMaps.push(depMap.normalizedMap || depMap);
                                  });
                                  req.onResourceLoad(context, this.map, resLoadMaps);
                              }
                          }
  
                          //Clean up
                          cleanRegistry(id);
  
                          this.defined = true;
                      }
  
                      //Finished the define stage. Allow calling check again
                      //to allow define notifications below in the case of a
                      //cycle.
                      this.defining = false;
  
                      if (this.defined && !this.defineEmitted) {
                          this.defineEmitted = true;
                          this.emit('defined', this.exports);
                          this.defineEmitComplete = true;
                      }
  
                  }
              },
  
              callPlugin: function () {
                  var map = this.map,
                      id = map.id,
                      //Map already normalized the prefix.
                      pluginMap = makeModuleMap(map.prefix);
  
                  //Mark this as a dependency for this plugin, so it
                  //can be traced for cycles.
                  this.depMaps.push(pluginMap);
  
                  on(pluginMap, 'defined', bind(this, function (plugin) {
                      var load, normalizedMap, normalizedMod,
                          bundleId = getOwn(bundlesMap, this.map.id),
                          name = this.map.name,
                          parentName = this.map.parentMap ? this.map.parentMap.name : null,
                          localRequire = context.makeRequire(map.parentMap, {
                              enableBuildCallback: true
                          });
  
                      //If current map is not normalized, wait for that
                      //normalized name to load instead of continuing.
                      if (this.map.unnormalized) {
                          //Normalize the ID if the plugin allows it.
                          if (plugin.normalize) {
                              name = plugin.normalize(name, function (name) {
                                  return normalize(name, parentName, true);
                              }) || '';
                          }
  
                          //prefix and name should already be normalized, no need
                          //for applying map config again either.
                          normalizedMap = makeModuleMap(map.prefix + '!' + name,
                                                        this.map.parentMap,
                                                        true);
                          on(normalizedMap,
                              'defined', bind(this, function (value) {
                                  this.map.normalizedMap = normalizedMap;
                                  this.init([], function () { return value; }, null, {
                                      enabled: true,
                                      ignore: true
                                  });
                              }));
  
                          normalizedMod = getOwn(registry, normalizedMap.id);
                          if (normalizedMod) {
                              //Mark this as a dependency for this plugin, so it
                              //can be traced for cycles.
                              this.depMaps.push(normalizedMap);
  
                              if (this.events.error) {
                                  normalizedMod.on('error', bind(this, function (err) {
                                      this.emit('error', err);
                                  }));
                              }
                              normalizedMod.enable();
                          }
  
                          return;
                      }
  
                      //If a paths config, then just load that file instead to
                      //resolve the plugin, as it is built into that paths layer.
                      if (bundleId) {
                          this.map.url = context.nameToUrl(bundleId);
                          this.load();
                          return;
                      }
  
                      load = bind(this, function (value) {
                          this.init([], function () { return value; }, null, {
                              enabled: true
                          });
                      });
  
                      load.error = bind(this, function (err) {
                          this.inited = true;
                          this.error = err;
                          err.requireModules = [id];
  
                          //Remove temp unnormalized modules for this module,
                          //since they will never be resolved otherwise now.
                          eachProp(registry, function (mod) {
                              if (mod.map.id.indexOf(id + '_unnormalized') === 0) {
                                  cleanRegistry(mod.map.id);
                              }
                          });
  
                          onError(err);
                      });
  
                      //Allow plugins to load other code without having to know the
                      //context or how to 'complete' the load.
                      load.fromText = bind(this, function (text, textAlt) {
                          /*jslint evil: true */
                          var moduleName = map.name,
                              moduleMap = makeModuleMap(moduleName),
                              hasInteractive = useInteractive;
  
                          //As of 2.1.0, support just passing the text, to reinforce
                          //fromText only being called once per resource. Still
                          //support old style of passing moduleName but discard
                          //that moduleName in favor of the internal ref.
                          if (textAlt) {
                              text = textAlt;
                          }
  
                          //Turn off interactive script matching for IE for any define
                          //calls in the text, then turn it back on at the end.
                          if (hasInteractive) {
                              useInteractive = false;
                          }
  
                          //Prime the system by creating a module instance for
                          //it.
                          getModule(moduleMap);
  
                          //Transfer any config to this other module.
                          if (hasProp(config.config, id)) {
                              config.config[moduleName] = config.config[id];
                          }
  
                          try {
                              req.exec(text);
                          } catch (e) {
                              return onError(makeError('fromtexteval',
                                               'fromText eval for ' + id +
                                              ' failed: ' + e,
                                               e,
                                               [id]));
                          }
  
                          if (hasInteractive) {
                              useInteractive = true;
                          }
  
                          //Mark this as a dependency for the plugin
                          //resource
                          this.depMaps.push(moduleMap);
  
                          //Support anonymous modules.
                          context.completeLoad(moduleName);
  
                          //Bind the value of that module to the value for this
                          //resource ID.
                          localRequire([moduleName], load);
                      });
  
                      //Use parentName here since the plugin's name is not reliable,
                      //could be some weird string with no path that actually wants to
                      //reference the parentName's path.
                      plugin.load(map.name, localRequire, load, config);
                  }));
  
                  context.enable(pluginMap, this);
                  this.pluginMaps[pluginMap.id] = pluginMap;
              },
  
              enable: function () {
                  enabledRegistry[this.map.id] = this;
                  this.enabled = true;
  
                  //Set flag mentioning that the module is enabling,
                  //so that immediate calls to the defined callbacks
                  //for dependencies do not trigger inadvertent load
                  //with the depCount still being zero.
                  this.enabling = true;
  
                  //Enable each dependency
                  each(this.depMaps, bind(this, function (depMap, i) {
                      var id, mod, handler;
  
                      if (typeof depMap === 'string') {
                          //Dependency needs to be converted to a depMap
                          //and wired up to this module.
                          depMap = makeModuleMap(depMap,
                                                 (this.map.isDefine ? this.map : this.map.parentMap),
                                                 false,
                                                 !this.skipMap);
                          this.depMaps[i] = depMap;
  
                          handler = getOwn(handlers, depMap.id);
  
                          if (handler) {
                              this.depExports[i] = handler(this);
                              return;
                          }
  
                          this.depCount += 1;
  
                          on(depMap, 'defined', bind(this, function (depExports) {
                              if (this.undefed) {
                                  return;
                              }
                              this.defineDep(i, depExports);
                              this.check();
                          }));
  
                          if (this.errback) {
                              on(depMap, 'error', bind(this, this.errback));
                          } else if (this.events.error) {
                              // No direct errback on this module, but something
                              // else is listening for errors, so be sure to
                              // propagate the error correctly.
                              on(depMap, 'error', bind(this, function(err) {
                                  this.emit('error', err);
                              }));
                          }
                      }
  
                      id = depMap.id;
                      mod = registry[id];
  
                      //Skip special modules like 'require', 'exports', 'module'
                      //Also, don't call enable if it is already enabled,
                      //important in circular dependency cases.
                      if (!hasProp(handlers, id) && mod && !mod.enabled) {
                          context.enable(depMap, this);
                      }
                  }));
  
                  //Enable each plugin that is used in
                  //a dependency
                  eachProp(this.pluginMaps, bind(this, function (pluginMap) {
                      var mod = getOwn(registry, pluginMap.id);
                      if (mod && !mod.enabled) {
                          context.enable(pluginMap, this);
                      }
                  }));
  
                  this.enabling = false;
  
                  this.check();
              },
  
              on: function (name, cb) {
                  var cbs = this.events[name];
                  if (!cbs) {
                      cbs = this.events[name] = [];
                  }
                  cbs.push(cb);
              },
  
              emit: function (name, evt) {
                  each(this.events[name], function (cb) {
                      cb(evt);
                  });
                  if (name === 'error') {
                      //Now that the error handler was triggered, remove
                      //the listeners, since this broken Module instance
                      //can stay around for a while in the registry.
                      delete this.events[name];
                  }
              }
          };
  
          function callGetModule(args) {
              //Skip modules already defined.
              if (!hasProp(defined, args[0])) {
                  getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]);
              }
          }
  
          function removeListener(node, func, name, ieName) {
              //Favor detachEvent because of IE9
              //issue, see attachEvent/addEventListener comment elsewhere
              //in this file.
              if (node.detachEvent && !isOpera) {
                  //Probably IE. If not it will throw an error, which will be
                  //useful to know.
                  if (ieName) {
                      node.detachEvent(ieName, func);
                  }
              } else {
                  node.removeEventListener(name, func, false);
              }
          }
  
          /**
           * Given an event from a script node, get the requirejs info from it,
           * and then removes the event listeners on the node.
           * @param {Event} evt
           * @returns {Object}
           */
          function getScriptData(evt) {
              //Using currentTarget instead of target for Firefox 2.0's sake. Not
              //all old browsers will be supported, but this one was easy enough
              //to support and still makes sense.
              var node = evt.currentTarget || evt.srcElement;
  
              //Remove the listeners once here.
              removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange');
              removeListener(node, context.onScriptError, 'error');
  
              return {
                  node: node,
                  id: node && node.getAttribute('data-requiremodule')
              };
          }
  
          function intakeDefines() {
              var args;
  
              //Any defined modules in the global queue, intake them now.
              takeGlobalQueue();
  
              //Make sure any remaining defQueue items get properly processed.
              while (defQueue.length) {
                  args = defQueue.shift();
                  if (args[0] === null) {
                      return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' +
                          args[args.length - 1]));
                  } else {
                      //args are id, deps, factory. Should be normalized by the
                      //define() function.
                      callGetModule(args);
                  }
              }
              context.defQueueMap = {};
          }
  
          context = {
              config: config,
              contextName: contextName,
              registry: registry,
              defined: defined,
              urlFetched: urlFetched,
              defQueue: defQueue,
              defQueueMap: {},
              Module: Module,
              makeModuleMap: makeModuleMap,
              nextTick: req.nextTick,
              onError: onError,
  
              /**
               * Set a configuration for the context.
               * @param {Object} cfg config object to integrate.
               */
              configure: function (cfg) {
                  //Make sure the baseUrl ends in a slash.
                  if (cfg.baseUrl) {
                      if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') {
                          cfg.baseUrl += '/';
                      }
                  }
  
                  // Convert old style urlArgs string to a function.
                  if (typeof cfg.urlArgs === 'string') {
                      var urlArgs = cfg.urlArgs;
                      cfg.urlArgs = function(id, url) {
                          return (url.indexOf('?') === -1 ? '?' : '&') + urlArgs;
                      };
                  }
  
                  //Save off the paths since they require special processing,
                  //they are additive.
                  var shim = config.shim,
                      objs = {
                          paths: true,
                          bundles: true,
                          config: true,
                          map: true
                      };
  
                  eachProp(cfg, function (value, prop) {
                      if (objs[prop]) {
                          if (!config[prop]) {
                              config[prop] = {};
                          }
                          mixin(config[prop], value, true, true);
                      } else {
                          config[prop] = value;
                      }
                  });
  
                  //Reverse map the bundles
                  if (cfg.bundles) {
                      eachProp(cfg.bundles, function (value, prop) {
                          each(value, function (v) {
                              if (v !== prop) {
                                  bundlesMap[v] = prop;
                              }
                          });
                      });
                  }
  
                  //Merge shim
                  if (cfg.shim) {
                      eachProp(cfg.shim, function (value, id) {
                          //Normalize the structure
                          if (isArray(value)) {
                              value = {
                                  deps: value
                              };
                          }
                          if ((value.exports || value.init) && !value.exportsFn) {
                              value.exportsFn = context.makeShimExports(value);
                          }
                          shim[id] = value;
                      });
                      config.shim = shim;
                  }
  
                  //Adjust packages if necessary.
                  if (cfg.packages) {
                      each(cfg.packages, function (pkgObj) {
                          var location, name;
  
                          pkgObj = typeof pkgObj === 'string' ? {name: pkgObj} : pkgObj;
  
                          name = pkgObj.name;
                          location = pkgObj.location;
                          if (location) {
                              config.paths[name] = pkgObj.location;
                          }
  
                          //Save pointer to main module ID for pkg name.
                          //Remove leading dot in main, so main paths are normalized,
                          //and remove any trailing .js, since different package
                          //envs have different conventions: some use a module name,
                          //some use a file name.
                          config.pkgs[name] = pkgObj.name + '/' + (pkgObj.main || 'main')
                                       .replace(currDirRegExp, '')
                                       .replace(jsSuffixRegExp, '');
                      });
                  }
  
                  //If there are any "waiting to execute" modules in the registry,
                  //update the maps for them, since their info, like URLs to load,
                  //may have changed.
                  eachProp(registry, function (mod, id) {
                      //If module already has init called, since it is too
                      //late to modify them, and ignore unnormalized ones
                      //since they are transient.
                      if (!mod.inited && !mod.map.unnormalized) {
                          mod.map = makeModuleMap(id, null, true);
                      }
                  });
  
                  //If a deps array or a config callback is specified, then call
                  //require with those args. This is useful when require is defined as a
                  //config object before require.js is loaded.
                  if (cfg.deps || cfg.callback) {
                      context.require(cfg.deps || [], cfg.callback);
                  }
              },
  
              makeShimExports: function (value) {
                  function fn() {
                      var ret;
                      if (value.init) {
                          ret = value.init.apply(global, arguments);
                      }
                      return ret || (value.exports && getGlobal(value.exports));
                  }
                  return fn;
              },
  
              makeRequire: function (relMap, options) {
                  options = options || {};
  
                  function localRequire(deps, callback, errback) {
                      var id, map, requireMod;
  
                      if (options.enableBuildCallback && callback && isFunction(callback)) {
                          callback.__requireJsBuild = true;
                      }
  
                      if (typeof deps === 'string') {
                          if (isFunction(callback)) {
                              //Invalid call
                              return onError(makeError('requireargs', 'Invalid require call'), errback);
                          }
  
                          //If require|exports|module are requested, get the
                          //value for them from the special handlers. Caveat:
                          //this only works while module is being defined.
                          if (relMap && hasProp(handlers, deps)) {
                              return handlers[deps](registry[relMap.id]);
                          }
  
                          //Synchronous access to one module. If require.get is
                          //available (as in the Node adapter), prefer that.
                          if (req.get) {
                              return req.get(context, deps, relMap, localRequire);
                          }
  
                          //Normalize module name, if it contains . or ..
                          map = makeModuleMap(deps, relMap, false, true);
                          id = map.id;
  
                          if (!hasProp(defined, id)) {
                              return onError(makeError('notloaded', 'Module name "' +
                                          id +
                                          '" has not been loaded yet for context: ' +
                                          contextName +
                                          (relMap ? '' : '. Use require([])')));
                          }
                          return defined[id];
                      }
  
                      //Grab defines waiting in the global queue.
                      intakeDefines();
  
                      //Mark all the dependencies as needing to be loaded.
                      context.nextTick(function () {
                          //Some defines could have been added since the
                          //require call, collect them.
                          intakeDefines();
  
                          requireMod = getModule(makeModuleMap(null, relMap));
  
                          //Store if map config should be applied to this require
                          //call for dependencies.
                          requireMod.skipMap = options.skipMap;
  
                          requireMod.init(deps, callback, errback, {
                              enabled: true
                          });
  
                          checkLoaded();
                      });
  
                      return localRequire;
                  }
  
                  mixin(localRequire, {
                      isBrowser: isBrowser,
  
                      /**
                       * Converts a module name + .extension into an URL path.
                       * *Requires* the use of a module name. It does not support using
                       * plain URLs like nameToUrl.
                       */
                      toUrl: function (moduleNamePlusExt) {
                          var ext,
                              index = moduleNamePlusExt.lastIndexOf('.'),
                              segment = moduleNamePlusExt.split('/')[0],
                              isRelative = segment === '.' || segment === '..';
  
                          //Have a file extension alias, and it is not the
                          //dots from a relative path.
                          if (index !== -1 && (!isRelative || index > 1)) {
                              ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length);
                              moduleNamePlusExt = moduleNamePlusExt.substring(0, index);
                          }
  
                          return context.nameToUrl(normalize(moduleNamePlusExt,
                                                  relMap && relMap.id, true), ext,  true);
                      },
  
                      defined: function (id) {
                          return hasProp(defined, makeModuleMap(id, relMap, false, true).id);
                      },
  
                      specified: function (id) {
                          id = makeModuleMap(id, relMap, false, true).id;
                          return hasProp(defined, id) || hasProp(registry, id);
                      }
                  });
  
                  //Only allow undef on top level require calls
                  if (!relMap) {
                      localRequire.undef = function (id) {
                          //Bind any waiting define() calls to this context,
                          //fix for #408
                          takeGlobalQueue();
  
                          var map = makeModuleMap(id, relMap, true),
                              mod = getOwn(registry, id);
  
                          mod.undefed = true;
                          removeScript(id);
  
                          delete defined[id];
                          delete urlFetched[map.url];
                          delete undefEvents[id];
  
                          //Clean queued defines too. Go backwards
                          //in array so that the splices do not
                          //mess up the iteration.
                          eachReverse(defQueue, function(args, i) {
                              if (args[0] === id) {
                                  defQueue.splice(i, 1);
                              }
                          });
                          delete context.defQueueMap[id];
  
                          if (mod) {
                              //Hold on to listeners in case the
                              //module will be attempted to be reloaded
                              //using a different config.
                              if (mod.events.defined) {
                                  undefEvents[id] = mod.events;
                              }
  
                              cleanRegistry(id);
                          }
                      };
                  }
  
                  return localRequire;
              },
  
              /**
               * Called to enable a module if it is still in the registry
               * awaiting enablement. A second arg, parent, the parent module,
               * is passed in for context, when this method is overridden by
               * the optimizer. Not shown here to keep code compact.
               */
              enable: function (depMap) {
                  var mod = getOwn(registry, depMap.id);
                  if (mod) {
                      getModule(depMap).enable();
                  }
              },
  
              /**
               * Internal method used by environment adapters to complete a load event.
               * A load event could be a script load or just a load pass from a synchronous
               * load call.
               * @param {String} moduleName the name of the module to potentially complete.
               */
              completeLoad: function (moduleName) {
                  var found, args, mod,
                      shim = getOwn(config.shim, moduleName) || {},
                      shExports = shim.exports;
  
                  takeGlobalQueue();
  
                  while (defQueue.length) {
                      args = defQueue.shift();
                      if (args[0] === null) {
                          args[0] = moduleName;
                          //If already found an anonymous module and bound it
                          //to this name, then this is some other anon module
                          //waiting for its completeLoad to fire.
                          if (found) {
                              break;
                          }
                          found = true;
                      } else if (args[0] === moduleName) {
                          //Found matching define call for this script!
                          found = true;
                      }
  
                      callGetModule(args);
                  }
                  context.defQueueMap = {};
  
                  //Do this after the cycle of callGetModule in case the result
                  //of those calls/init calls changes the registry.
                  mod = getOwn(registry, moduleName);
  
                  if (!found && !hasProp(defined, moduleName) && mod && !mod.inited) {
                      if (config.enforceDefine && (!shExports || !getGlobal(shExports))) {
                          if (hasPathFallback(moduleName)) {
                              return;
                          } else {
                              return onError(makeError('nodefine',
                                               'No define call for ' + moduleName,
                                               null,
                                               [moduleName]));
                          }
                      } else {
                          //A script that does not call define(), so just simulate
                          //the call for it.
                          callGetModule([moduleName, (shim.deps || []), shim.exportsFn]);
                      }
                  }
  
                  checkLoaded();
              },
  
              /**
               * Converts a module name to a file path. Supports cases where
               * moduleName may actually be just an URL.
               * Note that it **does not** call normalize on the moduleName,
               * it is assumed to have already been normalized. This is an
               * internal API, not a public one. Use toUrl for the public API.
               */
              nameToUrl: function (moduleName, ext, skipExt) {
                  var paths, syms, i, parentModule, url,
                      parentPath, bundleId,
                      pkgMain = getOwn(config.pkgs, moduleName);
  
                  if (pkgMain) {
                      moduleName = pkgMain;
                  }
  
                  bundleId = getOwn(bundlesMap, moduleName);
  
                  if (bundleId) {
                      return context.nameToUrl(bundleId, ext, skipExt);
                  }
  
                  //If a colon is in the URL, it indicates a protocol is used and it is just
                  //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?)
                  //or ends with .js, then assume the user meant to use an url and not a module id.
                  //The slash is important for protocol-less URLs as well as full paths.
                  if (req.jsExtRegExp.test(moduleName)) {
                      //Just a plain path, not module name lookup, so just return it.
                      //Add extension if it is included. This is a bit wonky, only non-.js things pass
                      //an extension, this method probably needs to be reworked.
                      url = moduleName + (ext || '');
                  } else {
                      //A module that needs to be converted to a path.
                      paths = config.paths;
  
                      syms = moduleName.split('/');
                      //For each module name segment, see if there is a path
                      //registered for it. Start with most specific name
                      //and work up from it.
                      for (i = syms.length; i > 0; i -= 1) {
                          parentModule = syms.slice(0, i).join('/');
  
                          parentPath = getOwn(paths, parentModule);
                          if (parentPath) {
                              //If an array, it means there are a few choices,
                              //Choose the one that is desired
                              if (isArray(parentPath)) {
                                  parentPath = parentPath[0];
                              }
                              syms.splice(0, i, parentPath);
                              break;
                          }
                      }
  
                      //Join the path parts together, then figure out if baseUrl is needed.
                      url = syms.join('/');
                      url += (ext || (/^data\:|^blob\:|\?/.test(url) || skipExt ? '' : '.js'));
                      url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url;
                  }
  
                  return config.urlArgs && !/^blob\:/.test(url) ?
                         url + config.urlArgs(moduleName, url) : url;
              },
  
              //Delegates to req.load. Broken out as a separate function to
              //allow overriding in the optimizer.
              load: function (id, url) {
                  req.load(context, id, url);
              },
  
              /**
               * Executes a module callback function. Broken out as a separate function
               * solely to allow the build system to sequence the files in the built
               * layer in the right sequence.
               *
               * @private
               */
              execCb: function (name, callback, args, exports) {
                  return callback.apply(exports, args);
              },
  
              /**
               * callback for script loads, used to check status of loading.
               *
               * @param {Event} evt the event from the browser for the script
               * that was loaded.
               */
              onScriptLoad: function (evt) {
                  //Using currentTarget instead of target for Firefox 2.0's sake. Not
                  //all old browsers will be supported, but this one was easy enough
                  //to support and still makes sense.
                  if (evt.type === 'load' ||
                          (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) {
                      //Reset interactive script so a script node is not held onto for
                      //to long.
                      interactiveScript = null;
  
                      //Pull out the name of the module and the context.
                      var data = getScriptData(evt);
                      context.completeLoad(data.id);
                  }
              },
  
              /**
               * Callback for script errors.
               */
              onScriptError: function (evt) {
                  var data = getScriptData(evt);
                  if (!hasPathFallback(data.id)) {
                      var parents = [];
                      eachProp(registry, function(value, key) {
                          if (key.indexOf('_@r') !== 0) {
                              each(value.depMaps, function(depMap) {
                                  if (depMap.id === data.id) {
                                      parents.push(key);
                                      return true;
                                  }
                              });
                          }
                      });
                      return onError(makeError('scripterror', 'Script error for "' + data.id +
                                               (parents.length ?
                                               '", needed by: ' + parents.join(', ') :
                                               '"'), evt, [data.id]));
                  }
              }
          };
  
          context.require = context.makeRequire();
          return context;
      }
  
      /**
       * Main entry point.
       *
       * If the only argument to require is a string, then the module that
       * is represented by that string is fetched for the appropriate context.
       *
       * If the first argument is an array, then it will be treated as an array
       * of dependency string names to fetch. An optional function callback can
       * be specified to execute when all of those dependencies are available.
       *
       * Make a local req variable to help Caja compliance (it assumes things
       * on a require that are not standardized), and to give a short
       * name for minification/local scope use.
       */
      req = requirejs = function (deps, callback, errback, optional) {
  
          //Find the right context, use default
          var context, config,
              contextName = defContextName;
  
          // Determine if have config object in the call.
          if (!isArray(deps) && typeof deps !== 'string') {
              // deps is a config object
              config = deps;
              if (isArray(callback)) {
                  // Adjust args if there are dependencies
                  deps = callback;
                  callback = errback;
                  errback = optional;
              } else {
                  deps = [];
              }
          }
  
          if (config && config.context) {
              contextName = config.context;
          }
  
          context = getOwn(contexts, contextName);
          if (!context) {
              context = contexts[contextName] = req.s.newContext(contextName);
          }
  
          if (config) {
              context.configure(config);
          }
  
          return context.require(deps, callback, errback);
      };
  
      /**
       * Support require.config() to make it easier to cooperate with other
       * AMD loaders on globally agreed names.
       */
      req.config = function (config) {
          return req(config);
      };
  
      /**
       * Execute something after the current tick
       * of the event loop. Override for other envs
       * that have a better solution than setTimeout.
       * @param  {Function} fn function to execute later.
       */
      req.nextTick = typeof setTimeout !== 'undefined' ? function (fn) {
          setTimeout(fn, 4);
      } : function (fn) { fn(); };
  
      /**
       * Export require as a global, but only if it does not already exist.
       */
      if (!require) {
          require = req;
      }
  
      req.version = version;
  
      //Used to filter out dependencies that are already paths.
      req.jsExtRegExp = /^\/|:|\?|\.js$/;
      req.isBrowser = isBrowser;
      s = req.s = {
          contexts: contexts,
          newContext: newContext
      };
  
      //Create default context.
      req({});
  
      //Exports some context-sensitive methods on global require.
      each([
          'toUrl',
          'undef',
          'defined',
          'specified'
      ], function (prop) {
          //Reference from contexts instead of early binding to default context,
          //so that during builds, the latest instance of the default context
          //with its config gets used.
          req[prop] = function () {
              var ctx = contexts[defContextName];
              return ctx.require[prop].apply(ctx, arguments);
          };
      });
  
      if (isBrowser) {
          head = s.head = document.getElementsByTagName('head')[0];
          //If BASE tag is in play, using appendChild is a problem for IE6.
          //When that browser dies, this can be removed. Details in this jQuery bug:
          //http://dev.jquery.com/ticket/2709
          baseElement = document.getElementsByTagName('base')[0];
          if (baseElement) {
              head = s.head = baseElement.parentNode;
          }
      }
  
      /**
       * Any errors that require explicitly generates will be passed to this
       * function. Intercept/override it if you want custom error handling.
       * @param {Error} err the error object.
       */
      req.onError = defaultOnError;
  
      /**
       * Creates the node for the load command. Only used in browser envs.
       */
      req.createNode = function (config, moduleName, url) {
          var node = config.xhtml ?
                  document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') :
                  document.createElement('script');
          node.type = config.scriptType || 'text/javascript';
          node.charset = 'utf-8';
          node.async = true;
          return node;
      };
  
      /**
       * Does the request to load a module for the browser case.
       * Make this a separate function to allow other environments
       * to override it.
       *
       * @param {Object} context the require context to find state.
       * @param {String} moduleName the name of the module.
       * @param {Object} url the URL to the module.
       */
      req.load = function (context, moduleName, url) {
          var config = (context && context.config) || {},
              node;
          if (isBrowser) {
              //In the browser so use a script tag
              node = req.createNode(config, moduleName, url);
  
              node.setAttribute('data-requirecontext', context.contextName);
              node.setAttribute('data-requiremodule', moduleName);
  
              //Set up load listener. Test attachEvent first because IE9 has
              //a subtle issue in its addEventListener and script onload firings
              //that do not match the behavior of all other browsers with
              //addEventListener support, which fire the onload event for a
              //script right after the script execution. See:
              //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution
              //UNFORTUNATELY Opera implements attachEvent but does not follow the script
              //script execution mode.
              if (node.attachEvent &&
                      //Check if node.attachEvent is artificially added by custom script or
                      //natively supported by browser
                      //read https://github.com/requirejs/requirejs/issues/187
                      //if we can NOT find [native code] then it must NOT natively supported.
                      //in IE8, node.attachEvent does not have toString()
                      //Note the test for "[native code" with no closing brace, see:
                      //https://github.com/requirejs/requirejs/issues/273
                      !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) &&
                      !isOpera) {
                  //Probably IE. IE (at least 6-8) do not fire
                  //script onload right after executing the script, so
                  //we cannot tie the anonymous define call to a name.
                  //However, IE reports the script as being in 'interactive'
                  //readyState at the time of the define call.
                  useInteractive = true;
  
                  node.attachEvent('onreadystatechange', context.onScriptLoad);
                  //It would be great to add an error handler here to catch
                  //404s in IE9+. However, onreadystatechange will fire before
                  //the error handler, so that does not help. If addEventListener
                  //is used, then IE will fire error before load, but we cannot
                  //use that pathway given the connect.microsoft.com issue
                  //mentioned above about not doing the 'script execute,
                  //then fire the script load event listener before execute
                  //next script' that other browsers do.
                  //Best hope: IE10 fixes the issues,
                  //and then destroys all installs of IE 6-9.
                  //node.attachEvent('onerror', context.onScriptError);
              } else {
                  node.addEventListener('load', context.onScriptLoad, false);
                  node.addEventListener('error', context.onScriptError, false);
              }
              node.src = url;
  
              //Calling onNodeCreated after all properties on the node have been
              //set, but before it is placed in the DOM.
              if (config.onNodeCreated) {
                  config.onNodeCreated(node, config, moduleName, url);
              }
  
              //For some cache cases in IE 6-8, the script executes before the end
              //of the appendChild execution, so to tie an anonymous define
              //call to the module name (which is stored on the node), hold on
              //to a reference to this node, but clear after the DOM insertion.
              currentlyAddingScript = node;
              if (baseElement) {
                  head.insertBefore(node, baseElement);
              } else {
                  head.appendChild(node);
              }
              currentlyAddingScript = null;
  
              return node;
          } else if (isWebWorker) {
              try {
                  //In a web worker, use importScripts. This is not a very
                  //efficient use of importScripts, importScripts will block until
                  //its script is downloaded and evaluated. However, if web workers
                  //are in play, the expectation is that a build has been done so
                  //that only one script needs to be loaded anyway. This may need
                  //to be reevaluated if other use cases become common.
  
                  // Post a task to the event loop to work around a bug in WebKit
  
                  // where the worker gets garbage-collected after calling
                  // importScripts(): https://webkit.org/b/153317
                  setTimeout(function() {}, 0);
                  importScripts(url);
  
                  //Account for anonymous modules
                  context.completeLoad(moduleName);
              } catch (e) {
                  context.onError(makeError('importscripts',
                                  'importScripts failed for ' +
                                      moduleName + ' at ' + url,
                                  e,
                                  [moduleName]));
              }
          }
      };
  
      function getInteractiveScript() {
          if (interactiveScript && interactiveScript.readyState === 'interactive') {
              return interactiveScript;
          }
  
          eachReverse(scripts(), function (script) {
              if (script.readyState === 'interactive') {
                  return (interactiveScript = script);
              }
          });
          return interactiveScript;
      }
  
      //Look for a data-main script attribute, which could also adjust the baseUrl.
      if (isBrowser && !cfg.skipDataMain) {
          //Figure out baseUrl. Get it from the script tag with require.js in it.
          eachReverse(scripts(), function (script) {
              //Set the 'head' where we can append children by
              //using the script's parent.
              if (!head) {
                  head = script.parentNode;
              }
  
              //Look for a data-main attribute to set main script for the page
              //to load. If it is there, the path to data main becomes the
              //baseUrl, if it is not already set.
              dataMain = script.getAttribute('data-main');
              if (dataMain) {
                  //Preserve dataMain in case it is a path (i.e. contains '?')
                  mainScript = dataMain;
  
                  //Set final baseUrl if there is not already an explicit one,
                  //but only do so if the data-main value is not a loader plugin
                  //module ID.
                  if (!cfg.baseUrl && mainScript.indexOf('!') === -1) {
                      //Pull off the directory of data-main for use as the
                      //baseUrl.
                      src = mainScript.split('/');
                      mainScript = src.pop();
                      subPath = src.length ? src.join('/')  + '/' : './';
  
                      cfg.baseUrl = subPath;
                  }
  
                  //Strip off any trailing .js since mainScript is now
                  //like a module name.
                  mainScript = mainScript.replace(jsSuffixRegExp, '');
  
                  //If mainScript is still a path, fall back to dataMain
                  if (req.jsExtRegExp.test(mainScript)) {
                      mainScript = dataMain;
                  }
  
                  //Put the data-main script in the files to load.
                  cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript];
  
                  return true;
              }
          });
      }
  
      /**
       * The function that handles definitions of modules. Differs from
       * require() in that a string for the module should be the first argument,
       * and the function to execute after dependencies are loaded should
       * return a value to define the module corresponding to the first argument's
       * name.
       */
      define = function (name, deps, callback) {
          var node, context;
  
          //Allow for anonymous modules
          if (typeof name !== 'string') {
              //Adjust args appropriately
              callback = deps;
              deps = name;
              name = null;
          }
  
          //This module may not have dependencies
          if (!isArray(deps)) {
              callback = deps;
              deps = null;
          }
  
          //If no name, and callback is a function, then figure out if it a
          //CommonJS thing with dependencies.
          if (!deps && isFunction(callback)) {
              deps = [];
              //Remove comments from the callback string,
              //look for require calls, and pull them into the dependencies,
              //but only if there are function args.
              if (callback.length) {
                  callback
                      .toString()
                      .replace(commentRegExp, commentReplace)
                      .replace(cjsRequireRegExp, function (match, dep) {
                          deps.push(dep);
                      });
  
                  //May be a CommonJS thing even without require calls, but still
                  //could use exports, and module. Avoid doing exports and module
                  //work though if it just needs require.
                  //REQUIRES the function to expect the CommonJS variables in the
                  //order listed below.
                  deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps);
              }
          }
  
          //If in IE 6-8 and hit an anonymous define() call, do the interactive
          //work.
          if (useInteractive) {
              node = currentlyAddingScript || getInteractiveScript();
              if (node) {
                  if (!name) {
                      name = node.getAttribute('data-requiremodule');
                  }
                  context = contexts[node.getAttribute('data-requirecontext')];
              }
          }
  
          //Always save off evaluating the def call until the script onload handler.
          //This allows multiple modules to be in a file without prematurely
          //tracing dependencies, and allows for anonymous module support,
          //where the module name is not known until the script onload event
          //occurs. If no context, use the global queue, and get it processed
          //in the onscript load callback.
          if (context) {
              context.defQueue.push([name, deps, callback]);
              context.defQueueMap[name] = true;
          } else {
              globalDefQueue.push([name, deps, callback]);
          }
      };
  
      define.amd = {
          jQuery: true
      };
  
      /**
       * Executes the text. Normally just uses eval, but can be modified
       * to use a better, environment-specific call. Only used for transpiling
       * loader plugins, not for plain JS modules.
       * @param {String} text the text to execute/evaluate.
       */
      req.exec = function (text) {
          /*jslint evil: true */
          return eval(text);
      };
  
      //Set up with config info.
      req(cfg);
  }(this, (typeof setTimeout === 'undefined' ? undefined : setTimeout)));
  
  /*
  * debouncedresize: special jQuery event that happens once after a window resize
  *
  * latest version and complete README available on Github:
  * https://github.com/louisremi/jquery-smartresize/blob/master/jquery.debouncedresize.js
  *
  * Copyright 2011 @louis_remi
  * Licensed under the MIT license.
  */
  var $event = $.event,
      $special,
      resizeTimeout;
  
  $special = $event.special.debouncedresize = {
      setup: function () {
          $(this).on("resize", $special.handler);
      },
      teardown: function () {
          $(this).off("resize", $special.handler);
      },
      handler: function (event, execAsap) {
          // Save the context
          var context = this,
              args = arguments,
              dispatch = function () {
                  // set correct event type
                  event.type = "debouncedresize";
                  $event.dispatch.apply(context, args);
              };
  
          if (resizeTimeout) {
              clearTimeout(resizeTimeout);
          }
  
          execAsap
              ? dispatch()
              : resizeTimeout = setTimeout(dispatch, $special.threshold);
      },
      threshold: 250
  };
  
  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;
    };
  }
  
  // Begin gatag.js
  
  //	This javascript tags file downloads and external links in Google Analytics.
  //	All outbound links and links to non-html files should now be automatically tracked.
  
  // Original script: http://www.goodwebpractices.com/roi/track-downloads-in-google-analytics-automatically.html
  // 5/16/11 Updated for asynchronous GA code.
  // 7/14/14 Added Office 2010 file extensions. Changed "click" to "mousedown". Added support for 2 dashboards.
  
  function addGAToDownloadLinks() {
  	if (document.getElementsByTagName) {
  		// Initialize external link handlers
  		var hrefs = document.getElementsByTagName("a");
  		for (var l = 0; l < hrefs.length; l++) {
  			// try {} catch{} block added by erikvold VKI
  			try{
  				//protocol, host, hostname, port, pathname, search, hash
  				if (hrefs[l].protocol == "mailto:") {
  					startListening(hrefs[l],"mousedown",trackMailto);
  				} else if (hrefs[l].protocol == "tel:") {
  					startListening(hrefs[l],"mousedown",trackTelto);
  				} else if (hrefs[l].hostname == location.host) {
  					var path = hrefs[l].pathname + hrefs[l].search;
  					var isDoc = path.match(/\.(?:doc|docx|eps|jpg|png|svg|xls|xlsx|ppt|pptx|pdf|zip|txt|vsd|vxd|js|css|rar|exe|wma|mov|avi|wmv|mp3)($|\&|\?)/);
  					if (isDoc) {
  						startListening(hrefs[l],"mousedown",trackExternalLinks);
  					}
  				} else if (!hrefs[l].href.match(/^javascript:/)) {
  					startListening(hrefs[l],"mousedown",trackExternalLinks);
  				}
  			}
  			catch(e){
  				continue;
  			}
  		}
  	}
  }
  
  function startListening (obj,evnt,func) {
  	if (obj.addEventListener) {
  		obj.addEventListener(evnt,func,false);
  	} else if (obj.attachEvent) {
  		obj.attachEvent("on" + evnt,func);
  	}
  }
  
  function trackMailto (evnt) {
  	var href = (evnt.srcElement) ? evnt.srcElement.href : this.href;
  	var mailto = "/mailto/" + href.substring(7);
  	_gaq.push(['_trackPageview', mailto]);
  	_gaq.push(['b._trackPageview', mailto]);
  }
  
  function trackTelto (evnt) {
  	var href = (evnt.srcElement) ? evnt.srcElement.href : this.href;
  	var telto = "/telto/" + href.substring(4);
  	_gaq.push(['_trackPageview', telto]);
  	_gaq.push(['b._trackPageview', telto]);
  }
  
  function trackExternalLinks (evnt) {
  	var e = (evnt.srcElement) ? evnt.srcElement : this;
  	while (e.tagName != "A") {
  		e = e.parentNode;
  	}
  	var lnk = (e.pathname.charAt(0) == "/") ? e.pathname : "/" + e.pathname;
  	if (e.search && e.pathname.indexOf(e.search) == -1) lnk += e.search;
  	if (e.hostname != location.host) lnk = "/external/" + e.hostname + lnk;
  	_gaq.push(['_trackPageview', lnk]);
  	_gaq.push(['b._trackPageview', lnk]);
  }
  
  // End gatag.js
  // End gatag.js
  /* -----------------------------------------
     NAVIGATION MENU - /source/js/cagov/navigation.js
  ----------------------------------------- */
  
  $(document).ready(function(){
    // detect partial flexbox support in IE>9
    if($('.top-level-nav').css('display') == 'table') { $('body').addClass('no-flex') }
  
    // menu variables
    var $navigation = $('#navigation.main-navigation'),
      $navItems = $navigation.find('.nav-item'), // first level link containers'
      $navItemsWithSubs = $navItems.has('.sub-nav'),
      $subNavs = $navigation.find('.sub-nav'),
      megamenu = $navigation.hasClass('megadropdown'),
      dropdown = $navigation.hasClass('dropdown'),
      singleLevel = $navigation.hasClass('singleLevel'),
      offCanvas = false; // beta 5.9 addition instead of: $navigation.hasClass('off-canvas'), 
      mobileWidth = 767,
      setActiveLinkByFolder = $navigation.hasClass('auto-highlight'); // Use new folder matching method to highlight the current navigation tab
  
    var mouseOverDelay=300, setTimeoutConst;
  
    // touch detection
    var isTouch = Modernizr.touch,
      msTouch	= (('ontouchstart' in window) || (navigator.MaxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0));
  
    var touchMode = false;
    $(window).on('mousemove',function(){
      if(touchMode) touchmode = false;
    });
  
    // HIGHLIGHT APPROPRIATE NAV ITEM
    var reMainNav = "",
      arrCurrentURL=location.href.split("/");
    if (typeof defaultActiveLink != "undefined") {
      reMainNav = new RegExp("^" + defaultActiveLink + "$", "i"); // Regex for finding the index of the default main list item
    }
    $navItems.each(function(){ // loop through top level links
      var $this = $(this),
        $a = $this.find('.first-level-link');
  
      if (reMainNav) {
        if($a.text().match(reMainNav)) {
          $this.addClass('active');
        }
      } else if(setActiveLinkByFolder && $a.attr('href')) {
        var arrNavLink = $a[0].href.split("/");
        if ((arrNavLink.length > 4) && (arrCurrentURL[3] == arrNavLink[3])) { // folder of current URL matches this nav link
          $this.addClass('active');
        }
      }
    });
  
    $navItemsWithSubs.each(function(){
      var itemCount = $(this).find('.second-level-nav > li').length;
      if(itemCount <= 2) {
        $(this).find('.sub-nav').addClass('with-few-items');
      }
    });
  
  
    if((megamenu || dropdown) && (isTouch || !msTouch)) {		// setup standard megamenu or dropdown menu and touch supporting 'ontouchstart'
      // show and hide sub nav with fade effect
      
   
      if(isTouch) {
        // hide submenus when touch occurs outside of menu
        $(document).on('touchstart.ca.catchNav', function(e) {
          touchMode = false;
          hideSubNavs();
        }, false);
  
        $navItemsWithSubs.each(function(){
          var $this = $(this),
            $a = $this.find('.first-level-link'),
            node = $a[0],
            $sub = $this.find('.sub-nav'),
            $subLinks = $sub.find('a');
          $a.data('link',$a.attr('href')).removeAttr; // store url
  
          $this.on('touchstart.ca.propagation', function(e) {
            // keeps tabpanel from closing when clicking inside of it
            e.stopPropagation();
          });
  
          $this.on('touchstart.ca.navclose', function(e) {
            touchMode = true;
            if($sub.is(':visible') || mobileView()) {
              // if sub is visible, or in mobile view keep default behavior
            } else {
              // keeps tabpanel from closing when clicking inside of it
              e.preventDefault();
              e.stopPropagation();
  
              // position arrow, hide other sub-nav panels, fade in current panel
            
              hideSubNavs();
              $sub.fadeIn(300);
            }
          },false);
        });
      }
  
    } else if((megamenu || dropdown) && msTouch) { 		// setup standard megamenu or dropdown menu and touch supporting 'pointerevents'
      // hide submenus when touch/click occurs outside of menu
      $(document).on('click.ca.catchNav',function(e){
        if (!$navigation.is(e.target) && $navigation.has(e.target).length === 0) {
          hideSubNavs();
        }
      });
  
      $navItemsWithSubs.each(function(){
        var $this = $(this),
          $a = $this.find('.first-level-link'),
          node = $a[0],
          $sub = $this.find('.sub-nav'),
          $subLinks = $sub.find('a');
        $a.data('link',$a.attr('href')); // store url
  
          $this.on('click.ca.propagation', function(e) {
          // keeps tabpanel from closing when clicking inside of it
          e.stopPropagation();
        });
  
        $a.on('click.ca.navclose', function(e) {
          if($sub.is(':visible') || mobileView()) {
            // if sub is visible, or in mobile view keep default behavior
          } else {
            // keeps tabpanel from closing when clicking inside of it
            e.preventDefault();
            e.stopPropagation();
  
            // position arrow, hide other sub-nav panels, fade in current panel
          
            hideSubNavs();
            $sub.fadeIn(300);
          }
        });
      });
    }
  
    // MENU FUNCTIONS
  
  
    function mobileView() {
      return ($('.global-header .mobile-controls').css('display') !== "none"); // mobile view uses arrow to show subnav instead of first touch
    }
  
  
  
    // SETUP MOBILE MENU
    // add sub nav toggles to mobile menu $navItemsWithSubs
    if(!singleLevel) {
      $navItemsWithSubs.each(function(){
  
        $(this).find('.first-level-link').addClass('has-sub');
  
        // create toggle object
        var $toggleSubNav = $('<span class="mobile-control toggle-sub-nav closed"><span class="ca-gov-icon-menu-toggle-closed" aria-hidden="true"></span><span class="ca-gov-icon-menu-toggle-open" aria-hidden="true"></span><span class="sr-only">Sub Menu Toggle</span></span>');
        // add toggle object to DOM
        $(this).find('.sub-nav').before($toggleSubNav);
  
        // setup mobile toggle
        $toggleSubNav.on("click", function () {
          var secondaryLinks = $(this).parent().find('.sub-nav');
          if(secondaryLinks.is(':visible')) {
            //close panel
            $(this).removeClass('open').addClass('closed');
            secondaryLinks.slideUp('fast',function(){
              // remove style attribute after animation and switch to class for styling
              $(this).removeAttr('style').removeClass('secondary-open');
            });
          } else {
            // open panel
            $(this).removeClass('closed').addClass('open');
            secondaryLinks.slideDown('fast',function(){
              // remove style attribute after animation and switch to class for styling
              $(this).removeAttr('style').addClass('secondary-open');
            });
          }
        });
      });
    }
  
   
      // Setup non-off-canvas menu
      $('#navigation').addClass('mobile-closed');
      $('.toggle-menu').on("click", function () {
          if ($('#navigation').hasClass('mobile-closed')) {
              $(this).attr('aria-expanded', 'true');
              $('#navigation').removeClass('mobile-closed');
          } else {
              $(this).attr('aria-expanded', 'false');
              $('#navigation').addClass('mobile-closed');
          }
        //$('#navigation').toggleClass('mobile-closed');
        $('.search-container').removeClass('active');
          // Changing aria attributes for accessibility
       
      });
  
      $('.toggle-search').on('click',function(){
        $('.search-container').toggleClass('active');
        if(!$('#navigation').hasClass('active')) {
          $('#navigation').addClass('mobile-closed');
        }
      });
    
  
  
    // allow dropdown on focus
    var menuHoverClass = 'focus',
      clickedFocus = 'clickedFocus';
  
    $('.top-level-nav > li > a').on("mouseenter", function () {
      $(this).closest('ul').find('.'+menuHoverClass).removeClass(menuHoverClass);
    }).on("mouseleave", function () {
          $('.' + clickedFocus).removeClass(clickedFocus);
    });
    $('.top-level-nav > li > a').on("focus", function (e) {
      $(this).closest('ul').find('.'+menuHoverClass).removeClass(menuHoverClass);
      if(!$(this).parent().find('.toggle-sub-nav').hasClass('open')) {
        $(this).parent().addClass(menuHoverClass);
      }
    }).on('mousedown',function(){
      // prevent subnav from showing when link is clicked
      if(!$(this).parent().find('.toggle-sub-nav').hasClass('open')) {
        $(this).parent().addClass(clickedFocus);
      }
    });
  
    // Hide menu if click occurs outside of navigation
    // Hide menu if click or focus occurs outside of navigation
    $('.top-level-nav a').last().on("keydown", function (e) {
      if(e.keyCode == 9) {
        // If the user tabs out of the navigation hide all menus
        $('.top-level-nav .'+menuHoverClass).removeClass(menuHoverClass);
      }
    });
    $(document).on("click", function () { $('.top-level-nav .' + menuHoverClass).removeClass(menuHoverClass); });
  
    $('.top-level-nav').on("click", function (e) {
      e.stopPropagation();
    });
    //*/
  
  
  });
  
  /*  ACCESSIBLE MENU */
  // source https://github.com/adobe-accessibility/Accessible-Mega-Menu/
  
   (function ($, window, document) {
              "use strict";
              var pluginName = "accessibleMenu",
                  defaults = {
                      navToggle: "#nav-toggle",
                      navId: "#navigation",
                      uuidPrefix: "accessible-menu", // unique ID's are required to indicate aria-owns, aria-controls and aria-labelledby
                      menuClass: "nav-menu", // default css class used to define the megamenu styling
                      topNavItemClass: "nav-item", // default css class for a top-level navigation item in the megamenu
                      panelClass: "accessible-menu-panel", // default css class for a megamenu panel
                      panelGroupClass: "accessible-menu-panel-group", // default css class for a group of items within a megamenu panel
                      hoverClass: "hover", // default css class for the hover state
                      focusClass: "focus", // default css class for the focus state
                      openClass: "open", // default css class for the open state
                      openDelay: 400, // default open delay when opening menu via mouseover
                      closeDelay: 500 // default close delay when on mouseout
                  },
                  Keyboard = {
                      BACKSPACE: 8,
                      COMMA: 188,
                      DELETE: 46,
                      DOWN: 40,
                      END: 35,
                      ENTER: 13,
                      ESCAPE: 27,
                      HOME: 36,
                      LEFT: 37,
                      PAGE_DOWN: 34,
                      PAGE_UP: 33,
                      PERIOD: 190,
                      RIGHT: 39,
                      SPACE: 32,
                      TAB: 9,
                      UP: 38,
                      keyMap: {
                          48: "0",
                          49: "1",
                          50: "2",
                          51: "3",
                          52: "4",
                          53: "5",
                          54: "6",
                          55: "7",
                          56: "8",
                          57: "9",
                          59: ";",
                          65: "a",
                          66: "b",
                          67: "c",
                          68: "d",
                          69: "e",
                          70: "f",
                          71: "g",
                          72: "h",
                          73: "i",
                          74: "j",
                          75: "k",
                          76: "l",
                          77: "m",
                          78: "n",
                          79: "o",
                          80: "p",
                          81: "q",
                          82: "r",
                          83: "s",
                          84: "t",
                          85: "u",
                          86: "v",
                          87: "w",
                          88: "x",
                          89: "y",
                          90: "z",
                          96: "0",
                          97: "1",
                          98: "2",
                          99: "3",
                          100: "4",
                          101: "5",
                          102: "6",
                          103: "7",
                          104: "8",
                          105: "9",
                          190: "."
                      }
                  };
              /**
               * @desc Creates a new accessible mega menu instance.
               * @param {jquery} element
               * @param {object} [options] Mega Menu options
               * @param {string} [options.uuidPrefix=accessible-menu] - Prefix for generated unique id attributes, which are required to indicate aria-owns, aria-controls and aria-labelledby
               * @param {string} [options.menuClass=accessible-menu] - CSS class used to define the megamenu styling
               * @param {string} [options.topNavItemClass=accessible-menu-top-nav-item] - CSS class for a top-level navigation item in the megamenu
               * @param {string} [options.panelClass=accessible-menu-panel] - CSS class for a megamenu panel
               * @param {string} [options.panelGroupClass=accessible-menu-panel-group] - CSS class for a group of items within a megamenu panel
               * @param {string} [options.hoverClass=hover] - CSS class for the hover state
               * @param {string} [options.focusClass=focus] - CSS class for the focus state
               * @param {string} [options.openClass=open] - CSS class for the open state
               * @constructor
               */
              function accessibleMenu(element, options) {
                  this.element = element;
  
                  // merge optional settings and defaults into settings
                  this.settings = $.extend({}, defaults, options);
  
                  this._defaults = defaults;
                  this._name = pluginName;
  
                  this.mouseTimeoutID = null;
                  this.focusTimeoutID = null;
                  this.mouseFocused = false;
                  this.justFocused = false;
  
                  this.init();
              }
  
  
  
              accessibleMenu.prototype = (function () {
  
                  /* private attributes and methods ------------------------ */
                  var uuid = 0,
                      keydownTimeoutDuration = 1000,
                      keydownSearchString = "",
                      isTouch = typeof window.hasOwnProperty === "function" && !!window.hasOwnProperty("ontouchstart"),
                      _getPlugin,
                      _addUniqueId,
                      _togglePanel,
                      _clickHandler,
                      _clickOutsideHandler,
                      _DOMAttrModifiedHandler,
                      _focusInHandler,
                      _focusOutHandler,
                      _keyDownHandler,
                      _mouseDownHandler,
                      _mouseOverHandler,
                      _mouseOutHandler,
                      _toggleExpandedEventHandlers;
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_getPlugin
                   * @desc Returns the parent accessibleMenu instance for a given element
                   * @param {jQuery} element
                   * @memberof jQuery.fn.accessibleMenu
                   * @inner
                   * @private
                   */
                  _getPlugin = function (element) {
                      return $(element).closest(':data(plugin_' + pluginName + ')').data("plugin_" + pluginName);
                  };
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_addUniqueId
                   * @desc Adds a unique id and element.
                   * The id string starts with the
                   * string defined in settings.uuidPrefix.
                   * @param {jQuery} element
                   * @memberof jQuery.fn.accessibleMenu
                   * @inner
                   * @private
                   */
                  _addUniqueId = function (element) {
                      element = $(element);
                      var settings = this.settings;
                      if (!element.attr("id")) {
                          element.attr("id", settings.uuidPrefix + "-" + new Date().getTime() + "-" + (++uuid));
                      }
                  };
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_togglePanel
                   * @desc Toggle the display of mega menu panels in response to an event.
                   * The optional boolean value 'hide' forces all panels to hide.
                   * @param {event} event
                   * @param {Boolean} [hide] Hide all mega menu panels when true
                   * @memberof jQuery.fn.accessibleMenu
                   * @inner
                   * @private
                   */
                  _togglePanel = function (event, hide) {
                      var target = $(event.target),
                          that = this,
                          settings = this.settings,
                          menu = this.menu,
                          topli = target.closest('.' + settings.topNavItemClass),
                          panel = target.hasClass(settings.panelClass) ? target : target.closest('.' + settings.panelClass),
                          newfocus;
  
                      _toggleExpandedEventHandlers.call(this, true);
  
                      if (hide) {
                          topli = menu.find('.' + settings.topNavItemClass + ' .' + settings.openClass + ':first').closest('.' + settings.topNavItemClass);
                          if (!(topli.is(event.relatedTarget) || topli.has(event.relatedTarget).length > 0)) {
                              if ((event.type === 'mouseout' || event.type === 'focusout') && topli.has(document.activeElement).length > 0) {
                                  return;
                              }
                              topli.find('[aria-expanded]')
                                  .attr('aria-expanded', 'false')
                                  .removeClass(settings.openClass)
                                  .filter('.' + settings.panelClass)
                                  .attr('aria-hidden', 'true');
                              if ((event.type === 'keydown' && event.keyCode === Keyboard.ESCAPE) || event.type === 'DOMAttrModified') {
                                  newfocus = topli.find(':tabbable:first');
                                  setTimeout(function () {
                                      menu.find('[aria-expanded].' + that.settings.panelClass).off('DOMAttrModified.accessible-menu');
                                      newfocus.trigger("focus");
                                      that.justFocused = false;
                                  }, 99);
                              }
                          } else if (topli.length === 0) {
                              menu.find('[aria-expanded=true]')
                                  .attr('aria-expanded', 'false')
                                  .removeClass(settings.openClass)
                                  .filter('.' + settings.panelClass)
                                  .attr('aria-hidden', 'true');
                          }
                      } else {
                          clearTimeout(that.focusTimeoutID);
                          topli.siblings()
                              .find('[aria-expanded]')
                              .attr('aria-expanded', 'false')
                              .removeClass(settings.openClass)
                              .filter('.' + settings.panelClass)
                              .attr('aria-hidden', 'true');
                          topli.find('[aria-expanded]')
                              .attr('aria-expanded', 'true')
                              .addClass(settings.openClass)
                              .filter('.' + settings.panelClass)
                              .attr('aria-hidden', 'false');
                          if (event.type === 'mouseover' && target.is(':tabbable') && topli.length === 1 && panel.length === 0 && menu.has(document.activeElement).length > 0) {
                              target.trigger("focus");
                              that.justFocused = false;
                          }
  
                          _toggleExpandedEventHandlers.call(that);
                      }
                  };
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_clickHandler
                   * @desc Handle click event on mega menu item
                   * @param {event} Event object
                   * @memberof jQuery.fn.accessibleMenu
                   * @inner
                   * @private
                   */
                  _clickHandler = function (event) {
                      var target = $(event.target).closest(':tabbable'),
                          topli = target.closest('.' + this.settings.topNavItemClass),
                          panel = target.closest('.' + this.settings.panelClass);
                      if (topli.length === 1
                              && panel.length === 0
                              && topli.find('.' + this.settings.panelClass).length === 1) {
                          if (!target.hasClass(this.settings.openClass)) {
                              event.preventDefault();
                              event.stopPropagation();
                              _togglePanel.call(this, event);
                              this.justFocused = false;
                          }
                          else {
                              if (this.justFocused) {
                                  event.preventDefault();
                                  event.stopPropagation();
                                  this.justFocused = false;
                              } else if (isTouch) {
                                 // event.preventDefault();
                                 // event.stopPropagation();
                                 // _togglePanel.call(this, event, target.hasClass(this.settings.openClass));
                              }
                          }
                      }
                  };
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_clickOutsideHandler
                   * @desc Handle click event outside of a the megamenu
                   * @param {event} Event object
                   * @memberof jQuery.fn.accessibleMenu
                   * @inner
                   * @private
                   */
                  _clickOutsideHandler = function (event) {
                      if ($(event.target).closest(this.menu).length === 0) {
                          event.preventDefault();
                          event.stopPropagation();
                          _togglePanel.call(this, event, true);
                      }
                  };
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_DOMAttrModifiedHandler
                   * @desc Handle DOMAttrModified event on panel to respond to Windows 8 Narrator ExpandCollapse pattern
                   * @param {event} Event object
                   * @memberof jQuery.fn.accessibleMenu
                   * @inner
                   * @private
                   */
                  _DOMAttrModifiedHandler = function (event) {
                      if (event.originalEvent.attrName === 'aria-expanded'
                              && event.originalEvent.newValue === 'false'
                              && $(event.target).hasClass(this.settings.openClass)) {
                          event.preventDefault();
                          event.stopPropagation();
                          _togglePanel.call(this, event, true);
                      }
                  };
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_focusInHandler
                   * @desc Handle focusin event on mega menu item.
                   * @param {event} Event object
                   * @memberof jQuery.fn.accessibleMenu
                   * @inner
                   * @private
                   */
                  _focusInHandler = function (event) {
                      clearTimeout(this.focusTimeoutID);
                      var target = $(event.target),
                          panel = target.closest('.' + this.settings.panelClass);
                      target
                          .addClass(this.settings.focusClass)
                          //.on('click.accessible-menu', $.proxy(_clickHandler, this));
                      this.justFocused = !this.mouseFocused;
                      this.mouseFocused = false;
                      if (this.panels.not(panel).filter('.' + this.settings.openClass).length) {
                          _togglePanel.call(this, event);
                      }
                  };
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_focusOutHandler
                   * @desc Handle focusout event on mega menu item.
                   * @param {event} Event object
                   * @memberof jQuery.fn.accessibleMenu
                   * @inner
                   * @private
                   */
                  _focusOutHandler = function (event) {
                      this.justFocused = false;
                      var that = this,
                          target = $(event.target),
                          topli = target.closest('.' + this.settings.topNavItemClass),
                          keepOpen = false;
                      target
                          .removeClass(this.settings.focusClass)
                          .off('click.accessible-menu');
  
                      if (window.cvox) {
                          // If ChromeVox is running...
                          that.focusTimeoutID = setTimeout(function () {
                              window.cvox.Api.getCurrentNode(function (node) {
                                  if (topli.has(node).length) {
                                      // and the current node being voiced is in
                                      // the mega menu, clearTimeout,
                                      // so the panel stays open.
                                      clearTimeout(that.focusTimeoutID);
                                  } else {
                                      that.focusTimeoutID = setTimeout(function (scope, event, hide) {
                                          _togglePanel.call(scope, event, hide);
                                      }, 275, that, event, true);
                                  }
                              });
                          }, 25);
                      } else {
                          that.focusTimeoutID = setTimeout(function () {
                              _togglePanel.call(that, event, true);
                          }, 300);
                      }
                  };
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_keyDownHandler
                   * @desc Handle keydown event on mega menu.
                   * @param {event} Event object
                   * @memberof jQuery.fn.accessibleMenu
                   * @inner
                   * @private
                   */
                  _keyDownHandler = function (event) {
                      var that = (this.constructor === accessibleMenu) ? this : _getPlugin(this), // determine the accessibleMenu plugin instance
                          settings = that.settings,
                          target = $($(this).is('.' + settings.hoverClass + ':tabbable') ? this : event.target), // if the element is hovered the target is this, otherwise, its the focused element
                          menu = that.menu,
                          topnavitems = that.topnavitems,
                          topli = target.closest('.' + settings.topNavItemClass),
                          tabbables = menu.find(':tabbable'),
                          panel = target.hasClass(settings.panelClass) ? target : target.closest('.' + settings.panelClass),
                          panelGroups = panel.find('.' + settings.panelGroupClass),
                          currentPanelGroup = target.closest('.' + settings.panelGroupClass),
                          next,
                          keycode = event.keyCode || event.which,
                          start,
                          i,
                          o,
                          label,
                          found = false,
                          newString = Keyboard.keyMap[event.keyCode] || '',
                          regex,
                          isTopNavItem = (topli.length === 1 && panel.length === 0);
  
                      if (target.is("input:focus, select:focus, textarea:focus, button:focus")) {
                          // if the event target is a form element we should handle keydown normally
                          return;
                      }
  
                      if (target.is('.' + settings.hoverClass + ':tabbable')) {
                          $('html').off('keydown.accessible-menu');
                      }
  
                      switch (keycode) {
                          case Keyboard.ESCAPE:
                              _togglePanel.call(that, event, true);
                              break;
                          case Keyboard.DOWN:
                              event.preventDefault();
                              if (isTopNavItem) {
                                  _togglePanel.call(that, event);
                                  found = (topli.find('.' + settings.panelClass + ' :tabbable:first').trigger("focus").length === 1);
                              } else {
                                  found = (tabbables.filter(':gt(' + tabbables.index(target) + '):first').trigger("focus").length === 1);
                              }
  
                              if (!found && window.opera && opera.toString() === "[object Opera]" && (event.ctrlKey || event.metaKey)) {
                                  tabbables = $(':tabbable');
                                  i = tabbables.index(target);
                                  found = ($(':tabbable:gt(' + $(':tabbable').index(target) + '):first').trigger("focus").length === 1);
                              }
                              break;
                          case Keyboard.UP:
                              event.preventDefault();
                              if (isTopNavItem && target.hasClass(settings.openClass)) {
                                  _togglePanel.call(that, event, true);
                                  next = topnavitems.filter(':lt(' + topnavitems.index(topli) + '):last');
                                  if (next.children('.' + settings.panelClass).length) {
                                      found = (next.children()
                                          .attr('aria-expanded', 'true')
                                          .addClass(settings.openClass)
                                          .filter('.' + settings.panelClass)
                                          .attr('aria-hidden', 'false')
                                          .find(':tabbable:last')
                                          .trigger("focus") === 1);
                                  }
                              } else if (!isTopNavItem) {
                                  found = (tabbables.filter(':lt(' + tabbables.index(target) + '):last').trigger("focus").length === 1);
                              }
  
                              if (!found && window.opera && opera.toString() === "[object Opera]" && (event.ctrlKey || event.metaKey)) {
                                  tabbables = $(':tabbable');
                                  i = tabbables.index(target);
                                  found = ($(':tabbable:lt(' + $(':tabbable').index(target) + '):first').trigger("focus").length === 1);
                              }
                              break;
                          case Keyboard.RIGHT:
                              event.preventDefault();
                              if (isTopNavItem) {
                                  found = (topnavitems.filter(':gt(' + topnavitems.index(topli) + '):first').find(':tabbable:first').trigger("focus").length === 1);
                              } else {
                                  if (panelGroups.length && currentPanelGroup.length) {
                                      // if the current panel contains panel groups, and we are able to focus the first tabbable element of the next panel group
                                      found = (panelGroups.filter(':gt(' + panelGroups.index(currentPanelGroup) + '):first').find(':tabbable:first').trigger("focus").length === 1);
                                  }
  
                                  if (!found) {
                                      found = (topli.find(':tabbable:first').trigger("focus").length === 1);
                                  }
                              }
                              break;
                          case Keyboard.LEFT:
                              event.preventDefault();
                              if (isTopNavItem) {
                                  found = (topnavitems.filter(':lt(' + topnavitems.index(topli) + '):last').find(':tabbable:first').trigger("focus").length === 1);
                              } else {
                                  if (panelGroups.length && currentPanelGroup.length) {
                                      // if the current panel contains panel groups, and we are able to focus the first tabbable element of the previous panel group
                                      found = (panelGroups.filter(':lt(' + panelGroups.index(currentPanelGroup) + '):last').find(':tabbable:first').trigger("focus").length === 1);
                                  }
  
                                  if (!found) {
                                      found = (topli.find(':tabbable:first').trigger("focus").length === 1);
                                  }
                              }
                              break;
                          case Keyboard.TAB:
                              i = tabbables.index(target);
                              if (event.shiftKey && isTopNavItem && target.hasClass(settings.openClass)) {
                                  _togglePanel.call(that, event, true);
                                  next = topnavitems.filter(':lt(' + topnavitems.index(topli) + '):last');
                                  if (next.children('.' + settings.panelClass).length) {
                                      found = next.children()
                                          .attr('aria-expanded', 'true')
                                          .addClass(settings.openClass)
                                          .filter('.' + settings.panelClass)
                                          .attr('aria-hidden', 'false')
                                          .find(':tabbable:last')
                                          .trigger("focus");
                                  }
                              } else if (event.shiftKey && i > 0) {
                                  found = (tabbables.filter(':lt(' + i + '):last').trigger("focus").length === 1);
                              } else if (!event.shiftKey && i < tabbables.length - 1) {
                                  found = (tabbables.filter(':gt(' + i + '):first').trigger("focus").length === 1);
                              } else if (window.opera && opera.toString() === "[object Opera]") {
                                  tabbables = $(':tabbable');
                                  i = tabbables.index(target);
                                  if (event.shiftKey) {
                                      found = ($(':tabbable:lt(' + $(':tabbable').index(target) + '):last').trigger("focus").length === 1);
                                  } else {
                                      found = ($(':tabbable:gt(' + $(':tabbable').index(target) + '):first').trigger("focus").length === 1);
                                  }
                              }
  
                              if (found) {
                                  event.preventDefault();
                              }
                              break;
                          case Keyboard.SPACE:
                              if (isTopNavItem) {
                                  event.preventDefault();
                                  _clickHandler.call(that, event);
                              } else {
                                  return true;
                              }
                              break;
                          case Keyboard.ENTER:
                              return true;
                              break;
                          default:
                              // alphanumeric filter
                              clearTimeout(this.keydownTimeoutID);
  
                              keydownSearchString += newString !== keydownSearchString ? newString : '';
  
                              if (keydownSearchString.length === 0) {
                                  return;
                              }
  
                              this.keydownTimeoutID = setTimeout(function () {
                                  keydownSearchString = '';
                              }, keydownTimeoutDuration);
  
                              if (isTopNavItem && !target.hasClass(settings.openClass)) {
                                  tabbables = tabbables.filter(':not(.' + settings.panelClass + ' :tabbable)');
                              } else {
                                  tabbables = topli.find(':tabbable');
                              }
  
                              if (event.shiftKey) {
                                  tabbables = $(tabbables.get()
                                      .reverse());
                              }
  
                              for (i = 0; i < tabbables.length; i++) {
                                  o = tabbables.eq(i);
                                  if (o.is(target)) {
                                      start = (keydownSearchString.length === 1) ? i + 1 : i;
                                      break;
                                  }
                              }
  
                              regex = new RegExp('^' + keydownSearchString.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'), 'i');
  
                              for (i = start; i < tabbables.length; i++) {
                                  o = tabbables.eq(i);
                                  label = $.trim(o.text());
                                  if (regex.test(label)) {
                                      found = true;
                                      o.trigger("focus");
                                      break;
                                  }
                              }
                              if (!found) {
                                  for (i = 0; i < start; i++) {
                                      o = tabbables.eq(i);
                                      label = $.trim(o.text());
                                      if (regex.test(label)) {
                                          o.trigger("focus");
                                          break;
                                      }
                                  }
                              }
                              break;
                      }
                      that.justFocused = false;
                  };
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_mouseDownHandler
                   * @desc Handle mousedown event on mega menu.
                   * @param {event} Event object
                   * @memberof accessibleMenu
                   * @inner
                   * @private
                   */
                  _mouseDownHandler = function (event) {
                      if ($(event.target).is(this.settings.panelClass) || $(event.target).closest(":focusable").length) {
                          this.mouseFocused = true;
                      }
                      clearTimeout(this.mouseTimeoutID);
                      this.mouseTimeoutID = setTimeout(function () {
                          clearTimeout(this.focusTimeoutID);
                      }, 1);
                  };
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_mouseOverHandler
                   * @desc Handle mouseover event on mega menu.
                   * @param {event} Event object
                   * @memberof jQuery.fn.accessibleMenu
                   * @inner
                   * @private
                   */
  
               
                  _mouseOverHandler = function (event) {
                      clearTimeout(this.mouseTimeoutID);
                      var that = this;
                      if ($(window).width() > 768) {
                          this.mouseTimeoutID = setTimeout(function () {
                              $(event.target).addClass(that.settings.hoverClass);
                             
                              _togglePanel.call(that, event);
                              if ($(event.target).is(':tabbable')) {
                                  $('html').on('keydown.accessible-menu', $.proxy(_keyDownHandler, event.target));
                              }
                          }, this.settings.openDelay);
                      }
                  };
  
                  /**
                   * @name jQuery.fn.accessibleMenu~_mouseOutHandler
                   * @desc Handle mouseout event on mega menu.
                   * @param {event} Event object
                   * @memberof jQuery.fn.accessibleMenu
                   * @inner
                   * @private
                   */
                  _mouseOutHandler = function (event) {
                      clearTimeout(this.mouseTimeoutID);
                      var that = this;
                      $(event.target)
                          .removeClass(that.settings.hoverClass);
  
                      that.mouseTimeoutID = setTimeout(function () {
                          _togglePanel.call(that, event, true);
                      }, this.settings.closeDelay);
                      if ($(event.target).is(':tabbable')) {
                          $('html').off('keydown.accessible-menu');
                      }
                     
                  };
  
                  _toggleExpandedEventHandlers = function (hide) {
                      var menu = this.menu;
                      if (hide) {
                          $('html').off('mouseup.outside-accessible-menu, touchend.outside-accessible-menu, mspointerup.outside-accessible-menu,  pointerup.outside-accessible-menu');
  
                          menu.find('[aria-expanded].' + this.settings.panelClass).off('DOMAttrModified.accessible-menu');
                      } else {
                          $('html').on('mouseup.outside-accessible-menu, touchend.outside-accessible-menu, mspointerup.outside-accessible-menu,  pointerup.outside-accessible-menu', $.proxy(_clickOutsideHandler, this));
  
                          /* Narrator in Windows 8 automatically toggles the aria-expanded property on double tap or click.
                             To respond to the change to collapse the panel, we must add a listener for a DOMAttrModified event. */
                          menu.find('[aria-expanded=true].' + this.settings.panelClass).on('DOMAttrModified.accessible-menu', $.proxy(_DOMAttrModifiedHandler, this));
                      }
                  };
  
                  /* public attributes and methods ------------------------- */
                  return {
                      constructor: accessibleMenu,
  
                      /**
                       * @lends jQuery.fn.accessibleMenu
                       * @desc Initializes an instance of the accessibleMenu plugins
                       * @memberof jQuery.fn.accessibleMenu
                       * @instance
                       */
                      init: function () {
                          var settings = this.settings,
                              nav = $(this.element),
                              menu = nav.children().first(),
                              topnavitems = menu.children();
                          this.start(settings, nav, menu, topnavitems);
                      },
  
                      start: function (settings, nav, menu, topnavitems) {
                          var that = this;
                          this.settings = settings;
                          this.menu = menu;
                          this.topnavitems = topnavitems;
  
                          nav.attr("role", "navigation");
                          menu.addClass(settings.menuClass);
                          topnavitems.each(function (i, topnavitem) {
                              var topnavitemlink, topnavitempanel;
                              topnavitem = $(topnavitem);
                              topnavitem.addClass(settings.topNavItemClass);
                              topnavitemlink = topnavitem.find(":tabbable:first");
                              topnavitempanel = topnavitem.children(":not(:tabbable):last");
                              _addUniqueId.call(that, topnavitemlink);
                              if (topnavitempanel.length) {
                                  _addUniqueId.call(that, topnavitempanel);
                                  topnavitemlink.attr({
                                      // "aria-haspopup": true,
                                      "aria-controls": topnavitempanel.attr("id"),
                                      "aria-expanded": false
                                  });
  
                                  topnavitempanel.attr({
                                      "role": "region",
                                      "aria-expanded": false,
                                      "aria-hidden": true
                                  })
                                      .addClass(settings.panelClass)
                                      .not("[aria-labelledby]")
                                      .attr("aria-labelledby", topnavitemlink.attr("id"));
                              }
                          });
  
                          this.panels = menu.find("." + settings.panelClass);
  
  
                          menu.on("focusin.accessible-menu", ":focusable, ." + settings.panelClass, $.proxy(_focusInHandler, this))
                              .on("focusout.accessible-menu", ":focusable, ." + settings.panelClass, $.proxy(_focusOutHandler, this))
                              .on("keydown.accessible-menu", $.proxy(_keyDownHandler, this))
                              .on("mouseover.accessible-menu", $.proxy(_mouseOverHandler, this))
                              .on("mouseout.accessible-menu", $.proxy(_mouseOutHandler, this))
                              .on("mousedown.accessible-menu", $.proxy(_mouseDownHandler, this));
  
                          if (isTouch) {
                              menu.on("touchstart.accessible-menu", $.proxy(_clickHandler, this));
                          }
  
                          menu.find("hr").attr("role", "separator");
  
                          if ($(document.activeElement).closest(menu).length) {
                              $(document.activeElement).trigger("focusin.accessible-menu");
                          }
  
  
  
                      },
  
                      /**
                       * @desc Get default values
                       * @example $(selector).accessibleMenu("getDefaults");
                       * @return {object}
                       * @memberof jQuery.fn.accessibleMenu
                       * @instance
                       */
                      getDefaults: function () {
                          return this._defaults;
                      },
  
                      /**
                       * @desc Get any option set to plugin using its name (as string)
                       * @example $(selector).accessibleMenu("getOption", some_option);
                       * @param {string} opt
                       * @return {string}
                       * @memberof jQuery.fn.accessibleMenu
                       * @instance
                       */
                      getOption: function (opt) {
                          return this.settings[opt];
                      },
  
                      /**
                       * @desc Get all options
                       * @example $(selector).accessibleMenu("getAllOptions");
                       * @return {object}
                       * @memberof jQuery.fn.accessibleMenu
                       * @instance
                       */
                      getAllOptions: function () {
                          return this.settings;
                      },
  
                      /**
                       * @desc Set option
                       * @example $(selector).accessibleMenu("setOption", "option_name",  "option_value",  reinitialize);
                       * @param {string} opt - Option name
                       * @param {string} val - Option value
                       * @param {boolean} [reinitialize] - boolean to re-initialize the menu.
                       * @memberof jQuery.fn.accessibleMenu
                       * @instance
                       */
                      setOption: function (opt, value, reinitialize) {
                          this.settings[opt] = value;
                          if (reinitialize) {
                              this.init();
                          }
                      }
                  };
              }());
  
              $.fn[pluginName] = function (options) {
                  return this.each(function () {
                      if (!$.data(this, "plugin_" + pluginName)) {
                          $.data(this, "plugin_" + pluginName, new $.fn[pluginName].accessibleMenu(this, options));
                      }
                  });
              };
  
              $.fn[pluginName].accessibleMenu = accessibleMenu;
  
              /* :focusable and :tabbable selectors from
                 https://raw.github.com/jquery/jquery-ui/master/ui/jquery.ui.core.js */
  
              /**
               * @private
               */
              function visible(element) {
                  return $.expr.pseudos.visible(element) && !$(element).parents().addBack().filter(function () {
                      return $.css(this, "visibility") === "hidden";
                  }).length;
              }
  
              /**
               * @private
               */
              function focusable(element, isTabIndexNotNaN) {
                  var map, mapName, img,
                      nodeName = element.nodeName.toLowerCase();
                  if ("area" === nodeName) {
                      map = element.parentNode;
                      mapName = map.name;
                      if (!element.href || !mapName || map.nodeName.toLowerCase() !== "map") {
                          return false;
                      }
                      img = $("img[usemap=#" + mapName + "]")[0];
                      return !!img && visible(img);
                  }
                  return (/input|select|textarea|button|object/.test(nodeName) ? !element.disabled :
                          "a" === nodeName ?
                                  element.href || isTabIndexNotNaN :
                                  isTabIndexNotNaN) &&
                                      // the element and all of its ancestors must be visible
                                      visible(element);
              }
  
              $.extend($.expr.pseudos, {
                  data: $.expr.createPseudo ? $.expr.createPseudo(function (dataName) {
                      return function (elem) {
                          return !!$.data(elem, dataName);
                      };
                  }) : // support: jQuery <1.8
                          function (elem, i, match) {
                              return !!$.data(elem, match[3]);
                          },
  
                  focusable: function (element) {
                      return focusable(element, !isNaN($.attr(element, "tabindex")));
                  },
  
                  tabbable: function (element) {
                      var tabIndex = $.attr(element, "tabindex"),
                          isTabIndexNaN = isNaN(tabIndex);
                      return (isTabIndexNaN || tabIndex >= 0) && focusable(element, !isTabIndexNaN);
                  }
              });
  
  
              // Resets navigation to defauilt state on resize.
              $(window).on('resize', function () {
                  $(".sub-nav").removeClass("open");
                  $(".sub-nav").removeClass("secondary-open");
                  $(".sub-nav").attr("aria-expanded", false);
                  $(".sub-nav").attr("aria-hidden", true);
                  $(".first-level-link").removeClass("open");
                  $(".first-level-link").removeClass("active");
                  $(".first-level-link").attr("aria-expanded", false);
                  $("#navigation").addClass("mobile-closed");
                  $(".toggle-sub-nav").removeClass("open");
                  $(".toggle-sub-nav").addClass("closed");
                  $(".nav-item").removeClass("active");
                  $(".toggle-menu").attr('aria-expanded', 'false');
              });
  
          }(jQuery, window, document));
  
  
          $("nav:first").accessibleMenu({
              navId: "#navigation",
              /* prefix for generated unique id attributes, which are required 
                 to indicate aria-owns, aria-controls and aria-labelledby */
              uuidPrefix: "accessible-menu",
              /* css class used to define the megamenu styling */
              menuClass: "nav-menu",
              /* css class for a top-level navigation item in the megamenu */
              topNavItemClass: "nav-item",
              /* css class for a megamenu panel */
              panelClass: "sub-nav",
              /* css class for a group of items within a megamenu panel */
              panelGroupClass: "sub-nav-group",
              /* css class for the hover state */
              hoverClass: "hover",
              /* css class for the focus state */
              focusClass: "focus",
              /* css class for the open state */
              openClass: "open"
          });
  
  /* -----------------------------------------
     ACCORDION LIST - /source/js/cagov/accordion.js
  ----------------------------------------- */
  
  // Adds tabindex=0 to toggle links
  // Hides the description by default for js users.
  // No-js users will see the descriptions expanded
  $(document).ready(function(){
      var descriptionDefault = $('.accordion-list').find('.description').hide().attr('aria-hidden', 'true'); // Hide the descriptions by default
      $('.accordion-list .toggle').attr('tabindex', '0').attr('aria-expanded', 'false'); // Add tabindex to toggle links and aria support
      
      $(".accordion-list .toggle").on("click", function (e) {
          var accdDesc = $(this).next(".description");
          
          if( accdDesc.is(":visible") ){
              // CLOSED STATE
  			accdDesc.slideUp('fast').removeClass('hide').attr('aria-hidden', 'true');
  			$(this).parent('li').removeClass('open');
  			$(this).attr('aria-expanded', 'false');
  		} else {
  			// OPEN STATE
              accdDesc.slideDown('fast').removeClass('hide').attr('aria-hidden', 'false');
  			$(this).parent('li').addClass('open');
  			$(this).attr('aria-expanded', 'true');
  		}
  		return false;
      });
  });
  
      /* Accessible list accordion */
       // Source: http://oaa-accessibility.org/examplep/accordian1/
  
       $(document).ready(function () {
  
           var panel1 = new tabpanel("accordion", true);
  		 // you can have more than one accordion on your webpage simply adding new tabpanel variable with new assigned id
  		 // eaxaple: var panel1 = new tabpanel("accordion2", true);
       });
  
       // 
       // keyCodes() is an object to contain keycodes needed for the application 
       // 
       function keyCodes() {
           // Define values for keycodes 
           this.tab = 9;
           this.enter = 13;
           this.esc = 27;
  
           this.space = 32;
           this.pageup = 33;
           this.pagedown = 34;
           this.end = 35;
           this.home = 36;
  
           this.left = 37;
           this.up = 38;
           this.right = 39;
           this.down = 40;
  
       } // end keyCodes 
  
       // 
       // tabpanel() is a class constructor to create a ARIA-enabled tab panel widget. 
       // 
       // @param (id string) id is the id of the div containing the tab panel. 
       // 
       // @param (accordian boolean) accordian is true if the tab panel should operate 
       //         as an accordian; false if a tab panel 
       // 
       // @return N/A 
       // 
       // Usage: Requires a div container and children as follows: 
       // 
       //         1. tabs/accordian headers have class 'tab' 
       // 
       //         2. panels are divs with class 'panel' 
       // 
       function tabpanel(id, accordian) {
  
           // define the class properties 
  
           this.panel_id = id; // store the id of the containing div 
           this.accordian = accordian; // true if this is an accordian control 
           this.$panel = $('#' + id);  // store the jQuery object for the panel 
           this.keys = new keyCodes(); // keycodes needed for event handlers 
           this.$tabs = this.$panel.find('.tab'); // Array of panel tabs. 
           this.$panels = this.$panel.children('.panel'); // Array of panel. 
  
           // Bind event handlers 
           this.bindHandlers();
  
           // Initialize the tab panel 
           this.init();
  
       } // end tabpanel() constructor 
  
       // 
       // Function init() is a member function to initialize the tab/accordian panel. Hides all panels. If a tab 
       // has the class 'selected', makes that panel visible; otherwise, makes first panel visible. 
       // 
       // @return N/A 
       // 
       tabpanel.prototype.init = function () {
           var $tab; // the selected tab - if one is selected 
  
           // add aria attributes to the panels 
           this.$panels.attr('aria-hidden', 'true');
  
           // hide all the panels 
           this.$panels.hide();
  
           // get the selected tab 
           $tab = this.$tabs.filter('.selected');
  
           if ($tab == undefined) {
               $tab = this.$tabs.first();
               $tab.addClass('selected');
           }
  
           // show the panel that the selected tab controls and set aria-hidden to false 
           this.$panel.find('#' + $tab.attr('aria-controls')).show().attr('aria-hidden', 'false');
  
       } // end init() 
  
       // 
       // Function switchTabs() is a member function to give focus to a new tab or accordian header. 
       // If it's a tab panel, the currently displayed panel is hidden and the panel associated with the new tab 
       // is displayed. 
       // 
       // @param ($curTab obj) $curTab is the jQuery object of the currently selected tab 
       // 
       // @param ($newTab obj) $newTab is the jQuery object of new tab to switch to 
       // 
       // @return N/A 
       // 
       tabpanel.prototype.switchTabs = function ($curTab, $newTab) {
  
           // Remove the highlighting from the current tab 
           $curTab.removeClass('selected focus');
  
           // remove tab from the tab order and update its aria-selected attribute 
           $curTab.attr('tabindex', '-1').attr('aria-selected', 'false');
  
  
           // Highlight the new tab and update its aria-selected attribute 
           $newTab.addClass('selected').attr('aria-selected', 'true');
  
           // If this is a tab panel, swap displayed tabs 
           if (this.accordian == false) {
               // hide the current tab panel and set aria-hidden to true 
               this.$panel.find('#' + $curTab.attr('aria-controls')).hide().attr('aria-hidden', 'true');
  
               // update the aria-expanded attribute for the old tab 
               $curTab.attr('aria-expanded', 'false');
  
               // show the new tab panel and set aria-hidden to false 
               this.$panel.find('#' + $newTab.attr('aria-controls')).show().attr('aria-hidden', 'false');
  
               // update the aria-expanded attribute for the new tab 
               $newTab.attr('aria-expanded', 'true');
  
               // get new list of focusable elements 
               this.$focusable.length = 0;
               this.$panels.find(':focusable');
           }
  
           // Make new tab navigable 
           $newTab.attr('tabindex', '0');
  
           // give the new tab focus 
           $newTab.trigger("focus");
  
       } // end switchTabs() 
  
       // 
       // Function togglePanel() is a member function to display or hide the panel 
       // associated with an accordian header. Function also binds a keydown handler to the focusable items 
       // in the panel when expanding and unbinds the handlers when collapsing. 
       // 
       // @param ($tab obj) $tab is the jQuery object of the currently selected tab 
       // 
       // @return N/A 
       // 
       tabpanel.prototype.togglePanel = function ($tab) {
  
           $panel = this.$panel.find('#' + $tab.attr('aria-controls'));
  
           if ($panel.attr('aria-hidden') == 'true') {
               $panel.attr('aria-hidden', 'false');
               $panel.slideDown(100);
               $tab.addClass('open');
               $tab.find('i').attr('class', 'ca-gov-icon-menu-toggle-open font-size-sm');
  
               // update the aria-expanded attribute 
               $tab.attr('aria-expanded', 'true');
           }
           else {
               $panel.attr('aria-hidden', 'true');
               $panel.slideUp(100);
               $tab.removeClass('open');
               $tab.find('i').attr('class', 'ca-gov-icon-menu-toggle-closed font-size-sm');
  
               // update the aria-expanded attribute 
               $tab.attr('aria-expanded', 'false');
           }
  
       } // end togglePanel() 
  
       // 
       // Function bindHandlers() is a member function to bind event handlers for the tabs 
       // 
       // @return N/A 
       // 
       tabpanel.prototype.bindHandlers = function () {
  
           var thisObj = this; // Store the this pointer for reference 
  
           ////////////////////////////// 
           // Bind handlers for the tabs / accordian headers 
  
           // bind a tab keydown handler 
           this.$tabs.on("keydown", function (e) {
               return thisObj.handleTabKeyDown($(this), e);
           });
  
           // bind a tab keypress handler 
           this.$tabs.on("keypress", function (e) {
               return thisObj.handleTabKeyPress($(this), e);
           });
  
           // bind a tab click handler 
           this.$tabs.on("click", function (e) {
               return thisObj.handleTabClick($(this), e);
           });
  
           // bind a tab focus handler 
           this.$tabs.on("focus", function (e) {
               return thisObj.handleTabFocus($(this), e);
           });
  
           // bind a tab blur handler 
           this.$tabs.on("blur", function (e) {
               return thisObj.handleTabBlur($(this), e);
           });
  
           ///////////////////////////// 
           // Bind handlers for the panels 
  
           // bind a keydown handlers for the panel focusable elements 
           this.$panels.on("keydown", function (e) {
               return thisObj.handlePanelKeyDown($(this), e);
           });
  
           // bind a keypress handler for the panel 
           this.$panels.on("keypress",function (e) {
               return thisObj.handlePanelKeyPress($(this), e);
           });
  
           // bind a panel click handler 
           this.$panels.on("click", function (e) {
               return thisObj.handlePanelClick($(this), e);
           });
  
       } // end bindHandlers() 
  
       // 
       // Function handleTabKeyDown() is a member function to process keydown events for a tab 
       // 
       // @param ($tab obj) $tab is the jquery object of the tab being processed 
       // 
       // @param (e obj) e is the associated event object 
       // 
       // @return (boolean) Returns true if propagating; false if consuming event 
       // 
       tabpanel.prototype.handleTabKeyDown = function ($tab, e) {
  
           if (e.altKey) {
               // do nothing 
               return true;
           }
  
           switch (e.keyCode) {
               case this.keys.enter:
               case this.keys.space: {
  
                   // Only process if this is an accordian widget 
                   if (this.accordian == true) {
                       // display or collapse the panel 
                       this.togglePanel($tab);
  
                       e.stopPropagation();
                       return false;
                   }
  
                   return true;
               }
               case this.keys.left:
               case this.keys.up: {
  
                   var thisObj = this;
                   var $prevTab; // holds jQuery object of tab from previous pass 
                   var $newTab; // the new tab to switch to 
  
                   if (e.ctrlKey) {
                       // Ctrl+arrow moves focus from panel content to the open 
                       // tab/accordian header. 
                   }
                   else {
                       var curNdx = this.$tabs.index($tab);
  
                       if (curNdx == 0) {
                           // tab is the first one: 
                           // set newTab to last tab 
                           $newTab = this.$tabs.last();
                       }
                       else {
                           // set newTab to previous 
                           $newTab = this.$tabs.eq(curNdx - 1);
                       }
  
                       // switch to the new tab 
                       this.switchTabs($tab, $newTab);
                   }
  
                   e.stopPropagation();
                   return false;
               }
               case this.keys.right:
               case this.keys.down: {
  
                   var thisObj = this;
                   var foundTab = false; // set to true when current tab found in array 
                   var $newTab; // the new tab to switch to 
  
                   var curNdx = this.$tabs.index($tab);
  
                   if (curNdx == this.$tabs.length - 1) {
                       // tab is the last one: 
                       // set newTab to first tab 
                       $newTab = this.$tabs.first();
                   }
                   else {
                       // set newTab to next tab 
                       $newTab = this.$tabs.eq(curNdx + 1);
                   }
  
                   // switch to the new tab 
                   this.switchTabs($tab, $newTab);
  
                   e.stopPropagation();
                   return false;
               }
               case this.keys.home: {
  
                   // switch to the first tab 
                   this.switchTabs($tab, this.$tabs.first());
  
                   e.stopPropagation();
                   return false;
               }
               case this.keys.end: {
  
                   // switch to the last tab 
                   this.switchTabs($tab, this.$tabs.last());
  
                   e.stopPropagation();
                   return false;
               }
           }
       } // end handleTabKeyDown() 
  
  
       // 
       // Function handleTabKeyPress() is a member function to process keypress events for a tab. 
       // 
       // 
       // @param ($tab obj) $tab is the jquery object of the tab being processed 
       // 
       // @param (e obj) e is the associated event object 
       // 
       // @return (boolean) Returns true if propagating; false if consuming event 
       // 
       tabpanel.prototype.handleTabKeyPress = function ($tab, e) {
  
           if (e.altKey) {
               // do nothing 
               return true;
           }
  
           switch (e.keyCode) {
               case this.keys.enter:
               case this.keys.space:
               case this.keys.left:
               case this.keys.up:
               case this.keys.right:
               case this.keys.down:
               case this.keys.home:
               case this.keys.end: {
                   e.stopPropagation();
                   return false;
               }
               case this.keys.pageup:
               case this.keys.pagedown: {
  
                   // The tab keypress handler must consume pageup and pagedown 
                   // keypresses to prevent Firefox from switching tabs 
                   // on ctrl+pageup and ctrl+pagedown 
  
                   if (!e.ctrlKey) {
                       return true;
                   }
  
                   e.stopPropagation();
                   return false;
               }
           }
  
           return true;
  
       } // end handleTabKeyPress() 
  
       // 
       // Function handleTabClick() is a member function to process click events for tabs 
       // 
       // @param ($tab object) $tab is the jQuery object of the tab being processed 
       // 
       // @param (e object) e is the associated event object 
       // 
       // @return (boolean) returns false 
       // 
       tabpanel.prototype.handleTabClick = function ($tab, e) {
  
           // make clicked tab navigable 
           $tab.attr('tabindex', '0').attr('aria-selected', 'true').addClass('selected');
  
           // remove all tabs from the tab order and update their aria-selected attribute 
           this.$tabs.not($tab).attr('tabindex', '-1').attr('aria-selected', 'false').removeClass('selected');
  
           // Expand the new panel 
           this.togglePanel($tab);
  
           e.stopPropagation();
           return false;
  
       } // end handleTabClick() 
  
       // 
       // Function handleTabFocus() is a member function to process focus events for tabs 
       // 
       // @param ($tab object) $tab is the jQuery object of the tab being processed 
       // 
       // @param (e object) e is the associated event object 
       // 
       // @return (boolean) returns true 
       // 
       tabpanel.prototype.handleTabFocus = function ($tab, e) {
  
           // Add the focus class to the tab 
           $tab.addClass('focus');
  
           return true;
  
       } // end handleTabFocus() 
  
       // 
       // Function handleTabBlur() is a member function to process blur events for tabs 
       // 
       // @param ($tab object) $tab is the jQuery object of the tab being processed 
       // 
       // @param (e object) e is the associated event object 
       // 
       // @return (boolean) returns true 
       // 
       tabpanel.prototype.handleTabBlur = function ($tab, e) {
  
           // Remove the focus class to the tab 
           $tab.removeClass('focus');
  
           return true;
  
       } // end handleTabBlur() 
  
  
       ///////////////////////////////////////////////////////// 
       // Panel Event handlers 
       // 
  
       // 
       // Function handlePanelKeyDown() is a member function to process keydown events for a panel 
       // 
       // @param ($panel obj) $panel is the jquery object of the panel being processed 
       // 
       // @param (e obj) e is the associated event object 
       // 
       // @return (boolean) Returns true if propagating; false if consuming event 
       // 
       tabpanel.prototype.handlePanelKeyDown = function ($panel, e) {
  
           if (e.altKey) {
               // do nothing 
               return true;
           }
  
           switch (e.keyCode) {
               case this.keys.tab: {
                   var $focusable = $panel.find(':focusable');
                   var curNdx = $focusable.index($(e.target));
                   var panelNdx = this.$panels.index($panel);
                   var numPanels = this.$panels.length
  
                   if (e.shiftKey) {
                       // if this is the first focusable item in the panel 
                       // find the preceding expanded panel (if any) that has 
                       // focusable items and set focus to the last one in that 
                       // panel. If there is no preceding panel or no focusable items 
                       // do not process. 
                       if (curNdx == 0 && panelNdx > 0) {
  
                           // Iterate through previous panels until we find one that 
                           // is expanded and has focusable elements 
                           // 
                           for (var ndx = panelNdx - 1; ndx >= 0; ndx--) {
  
                               var $prevPanel = this.$panels.eq(ndx);
                               var $prevTab = $('#' + $prevPanel.attr('aria-labelledby'));
  
                               // get the focusable items in the panel 
                               $focusable.length = 0;
                               $focusable = $prevPanel.find(':focusable');
  
                               if ($focusable.length > 0) {
                                   // there are focusable items in the panel. 
                                   // Set focus to the last item. 
                                   $focusable.last().trigger("focus");
  
                                   // reset the aria-selected state of the tabs 
                                   this.$tabs.attr('aria-selected', 'false').removeClass('selected');
  
                                   // set the associated tab's aria-selected state 
                                   $prevTab.attr('aria-selected', 'true').addClass('selected');
  
                                   e.stopPropagation;
                                   return false;
                               }
                           }
                       }
                   }
                   else if (panelNdx < numPanels) {
  
                       // if this is the last focusable item in the panel 
                       // find the nearest following expanded panel (if any) that has 
                       // focusable items and set focus to the first one in that 
                       // panel. If there is no preceding panel or no focusable items 
                       // do not process. 
                       if (curNdx == $focusable.length - 1) {
  
                           // Iterate through following panels until we find one that 
                           // is expanded and has focusable elements 
                           // 
                           for (var ndx = panelNdx + 1; ndx < numPanels; ndx++) {
  
                               var $nextPanel = this.$panels.eq(ndx);
                               var $nextTab = $('#' + $nextPanel.attr('aria-labelledby'));
  
                               // get the focusable items in the panel 
                               $focusable.length = 0;
                               $focusable = $nextPanel.find(':focusable');
  
                               if ($focusable.length > 0) {
                                   // there are focusable items in the panel. 
                                   // Set focus to the first item. 
                                   $focusable.first().trigger("focus");
  
                                   // reset the aria-selected state of the tabs 
                                   this.$tabs.attr('aria-selected', 'false').removeClass('selected');
  
                                   // set the associated tab's aria-selected state 
                                   $nextTab.attr('aria-selected', 'true').addClass('selected');
  
                                   e.stopPropagation;
                                   return false;
                               }
                           }
                       }
                   }
  
                   break;
               }
               case this.keys.left:
               case this.keys.up: {
  
                   if (!e.ctrlKey) {
                       // do not process 
                       return true;
                   }
  
                   // get the jQuery object of the tab 
                   var $tab = $('#' + $panel.attr('aria-labelledby'));
  
                   // Move focus to the tab 
                   $tab.trigger("focus");
  
                   e.stopPropagation();
                   return false;
               }
               case this.keys.pageup: {
  
                   var $newTab;
  
                   if (!e.ctrlKey) {
                       // do not process 
                       return true;
                   }
  
                   // get the jQuery object of the tab 
                   var $tab = this.$tabs.filter('.selected');
  
                   // get the index of the tab in the tab list 
                   var curNdx = this.$tabs.index($tab);
  
                   if (curNdx == 0) {
                       // this is the first tab, set focus on the last one 
                       $newTab = this.$tabs.last();
                   }
                   else {
                       // set focus on the previous tab 
                       $newTab = this.$tabs.eq(curNdx - 1);
                   }
  
                   // switch to the new tab 
                   this.switchTabs($tab, $newTab);
  
                   e.stopPropagation();
                   e.preventDefault();
                   return false;
               }
               case this.keys.pagedown: {
  
                   var $newTab;
  
                   if (!e.ctrlKey) {
                       // do not process 
                       return true;
                   }
  
                   // get the jQuery object of the tab 
                   var $tab = $('#' + $panel.attr('aria-labelledby'));
  
                   // get the index of the tab in the tab list 
                   var curNdx = this.$tabs.index($tab);
  
                   if (curNdx == this.$tabs.length - 1) {
                       // this is the last tab, set focus on the first one 
                       $newTab = this.$tabs.first();
                   }
                   else {
                       // set focus on the next tab 
                       $newTab = this.$tabs.eq(curNdx + 1);
                   }
  
                   // switch to the new tab 
                   this.switchTabs($tab, $newTab);
  
                   e.stopPropagation();
                   e.preventDefault();
                   return false;
               }
           }
  
           return true;
  
       } // end handlePanelKeyDown() 
  
       // 
       // Function handlePanelKeyPress() is a member function to process keypress events for a panel 
       // 
       // @param ($panel obj) $panel is the jquery object of the panel being processed 
       // 
       // @param (e obj) e is the associated event object 
       // 
       // @return (boolean) Returns true if propagating; false if consuming event 
       // 
       tabpanel.prototype.handlePanelKeyPress = function ($panel, e) {
  
           if (e.altKey) {
               // do nothing 
               return true;
           }
  
           if (e.ctrlKey && (e.keyCode == this.keys.pageup || e.keyCode == this.keys.pagedown)) {
               e.stopPropagation();
               e.preventDefault();
               return false;
           }
  
           switch (e.keyCode) {
               case this.keys.esc: {
                   e.stopPropagation();
                   e.preventDefault();
                   return false;
               }
           }
  
           return true;
  
       } // end handlePanelKeyPress() 
  
       // 
       // Function handlePanelClick() is a member function to process click events for panels 
       // 
       // @param ($panel object) $panel is the jQuery object of the panel being processed 
       // 
       // @param (e object) e is the associated event object 
       // 
       // @return (boolean) returns true 
       // 
       tabpanel.prototype.handlePanelClick = function ($panel, e) {
  
           var $tab = $('#' + $panel.attr('aria-labelledby'));
  
           // make clicked panel's tab navigable 
           $tab.attr('tabindex', '0').attr('aria-selected', 'true').addClass('selected');
  
           // remove all tabs from the tab order and update their aria-selected attribute 
           this.$tabs.not($tab).attr('tabindex', '-1').attr('aria-selected', 'false').removeClass('selected');
  
           return true;
  
       } // end handlePanelClick() 
  
       // focusable is a small jQuery extension to add a :focusable selector. It is used to 
       // get a list of all focusable elements in a panel. Credit to ajpiano on the jQuery forums. 
       // 
       $.extend($.expr.pseudos, {
           focusable: function (element) {
               var nodeName = element.nodeName.toLowerCase();
               var tabIndex = $(element).attr('tabindex');
  
               // the element and all of its ancestors must be visible 
               if (($(element)[(nodeName == 'area' ? 'parents' : 'closest')](':hidden').length) == true) {
                   return false;
               }
  
               // If tabindex is defined, its value must be greater than 0 
               if (!isNaN(tabIndex) && tabIndex < 0) {
                   return false;
               }
  
               // if the element is a standard form control, it must not be disabled 
               if (/input|select|textarea|button|object/.test(nodeName) == true) {
  
                   return !element.disabled;
               }
  
               // if the element is a link, href must be defined 
               if ((nodeName == 'a' || nodeName == 'area') == true) {
  
                   return (element.href.length > 0);
               }
  
               // this is some other page element that is not normally focusable. 
               return false;
           }
       });
  
  
  
  
  /* -----------------------------------------
     PANELS - /source/js/cagov/panel.js
  ----------------------------------------- */
  
  $(document).ready(function(){ 
      // Finds the first panel in the sidebar
      // Adds the "first" class
      $(".main-secondary .panel").first().addClass("first");
         
      // Add a hook to the standout panel for adding a triangle
      $(".panel.highlight").find(".panel-heading").prepend( "<span class='triangle'></span>" );
  });
  
  /* -----------------------------------------
     SEARCH - /source/js/cagov/search.js
  ----------------------------------------- */
  
  $(document).ready(function () {
      var $searchContainer = $("#head-search");
      var $searchText = $searchContainer.find(".search-textfield");
      var $resultsContainer =$('.search-results-container');
  
      var $body = $("body");
      var $specialIcon =
      // setup the tabs
      $('.search-tabs button').on("click", function (e) {
          $(this).siblings().removeClass('active');
          $(this).tab('show').addClass('active');
          e.preventDefault()
      });
  
      // Unfreeze search width when blured.
      // Unfreeze search width when blured.
      $searchText.on('blur focus', function (e) {
          $(this).parents("#head-search").removeClass("focus");
          $(this).parents(".search-container").addClass("focus");
      });
  
      $searchText.on("change keyup paste", function () {
          if ($(this).val()) {
              addSearchResults();
          }
      });
  
      // have the close button remove search results and the applied classes
      $resultsContainer.find('.close').on('click', removeSearchResults);
      $searchContainer.find('.close').on('click', removeSearchResults);
  
      // Our special nav icon which we need to hook into for starting the search
      // $('#nav-item-search')
  
      // Sitecore link data types currently do not have a way to set id's per nav,
      // so instead we are binding to what I'm assuming will aslways be the search
      $('.top-level-nav .nav-item .ca-gov-icon-search, #nav-item-search').parents('.nav-item').on('click', function (e) {
          $searchText.trigger("focus").trigger('focus')
          // // already opened search, nothing else needs to be done
          // if ($searchContainer.hasClass('active')) {
          //     return;
          // }
  
          // let the user know the input box is where they should search
          $("#head-search").addClass('play-animation').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {
              $(this).removeClass('play-animation');
  
          });
  
  
          // When compact has been applied to the header, it will take 400ms
          // unitll the window has scrolled, and it will keep removing the ".active" class. After that we can apply the active
          // class.
  
  		//------------------------------------------------------------- v5 ----------------------------------------- *Changes to remove .primary body class dependency for featured-search behaviour 
  		
  		if ( $( "#head-search" ).is( ".featured-search" ) ) {
  		//-------------- v5 *Added if statement
          window.setTimeout(function() {
              $('body:not(.primary) .search-container').addClass('active');
          } ,401);
  		
  		}else{
  		
  		 window.setTimeout(function() {
              $('.search-container').addClass('active');
          } ,401);	
  
  		}
  		
      });
  
      // SEE navitgation.js for mobile click handlers
  
      // Close search when close icon is clicked
      $('.close-search').on('click', removeSearchResults);
  
      // Helpers
      function addSearchResults() {
          $body.addClass("active-search");
          $searchContainer.addClass('active');
          $resultsContainer.addClass('visible');
          // close the the menu when we are search
          $('#navigation').addClass('mobile-closed');
          // hide the ask group as well
          $('.ask-group').addClass('fade-out');
  
          // fire a scroll event to help update headers if need be
          $(window).scroll();
  
          $.event.trigger('cagov.searchresults.show');
      }
  
      function removeSearchResults() {
          $body.removeClass("active-search");
          $searchText.val('');
          $searchContainer.removeClass('active');
          $resultsContainer.removeClass('visible');
          $('.ask-group').removeClass('fade-out');
  
          // fire a scroll event to help update headers if need be
          $(window).scroll();
  
          $.event.trigger('cagov.searchresults.hide');
      }
  
  
  
  });
  
  /* -----------------------------------------
     INIT THIRD PARTY PLUGINS - /source/js/cagov/plugins.js
  ----------------------------------------- */
  
  requirejs.config({
      //By default load any module IDs from js/lib
      baseUrl: '/js/libs'
  });
  
  $(document).ready(function () {
      // Tabs to accordion
      // https://github.com/openam/bootstrap-responsive-tabs
      fakewaffle.responsiveTabs(['xs', 'sm']);
      
      // https://github.com/jsliang/eqHeight.coffee
      // Generic EQ Heights for top level children
      // Example: Use on .group to effect columns
      $(".eqHeight").eqHeight();
  });
  
  /* -----------------------------------------
     GALLERY - /source/js/cagov/gallery.js
  ----------------------------------------- */
      
  $(document).ready(function(){
  	// Requires fancyBox v2.1.5
      // Enable lightbox functionality
      $('.gallery .item a, .carousel-gallery .item a, a.gallery-item').fancybox({groupAttr: "data-gallery"});
      
      //   EQ Heights for Gallery Items
      $(".gallery").eqHeight(".item");
      
      // Trick eqHeights into running as tabs are focused so image galleries in tabs get height applied.
      // eqHeight plugin would not run using normal selection methods. Triggering resize event to trick eqHeight to run on tab focus
      $('a[data-toggle="tab"]').on('shown.bs.tab', function (e){
          window.dispatchEvent(new Event('resize'));
      });
  });
  /* -----------------------------------------
     PROFILE BANNERS
  ----------------------------------------- */
  
  $(document).ready(function(){
      // If using profile banners side by side in a .half this equal heights function will ensure they are the same height.
      $(".main-secondary").eqHeight(".profile-banner > .inner");
  });
  /* -----------------------------------------
     CAROUSEL INIT - /source/js/cagov/carousel.js
  ----------------------------------------- */
  
  $(document).ready(function () {
  
      $(".carousel-video").initCAVideo();
      $('.carousel-content').each(initContent);
  
      // Owl Carousel https://github.com/OwlFonk/OwlCarousel2 Requires Owl Carousel
      // 2.0.3+ Banner Carousel Plugin
      (function ($) {
          $.fn.owlBannerCarousel = function (options) {
              var settings = $.extend({
                  delay: 4000,
                  smallSearch: true
              }, options);
  
              return this.each(function () {
                  if (settings.smallSearch) {
                      $('.navigation-search').addClass('small-search');
                  }
  
                  var headerSlider = $('.header-slideshow-banner');
                  headerSlider.addClass('enabled');
  
                  // calculate top of screen on next repaint
                  window.setTimeout(function () {
                      var MAXHEIGHT = 450;
                      var headerTop = headerSlider.offset().top;
                      var windowHeight = $(window).height();
                      var height = windowHeight - headerTop;
                      height = (height > MAXHEIGHT)
                          ? MAXHEIGHT
                          : height;
                      // fill up the remaining heaight of this device
                      headerSlider.css({'height': height});
                  }, 0)
  
                  var $this = $(this);
  
                  // If browser is IE9 and below set transition speed to 0
                  var transitionSpeed = (!$('html').hasClass('oldie'))
                      ? 250
                      : 0;
  
                  // Initiate carousel
                  $this.owlCarousel({
                      //responsiveRefreshRate: 0,
                      items: 1,
                      smartSpeed: transitionSpeed,
                      animateOut: 'fadeOut',
                      loop: true,
                      autoplay: true,
                      autoplayTimeout: settings.delay,
                      autoplayHoverPause: false,
                      mouseDrag: false,
                      touchDrag: false,
                      pullDrag: false,
                      pagination: true,
                      dotsClass: 'banner-pager', dotClass: 'banner-control',
                      dotsContainer: false
                  });
  
                  // Add pause and play buttons
                  var owlBannerControl = $('<div class="banner-play-pause"><div class="banner-control"><span class="play ca-gov-icon-carousel-play" aria-hidden="true"></span><span class="pause ca-gov-icon-carousel-pause" aria-hidden="true"></span></div></div>');
                  $this.append(owlBannerControl); 
                  var playControl = owlBannerControl.find('.play').hide(); 
                  var pauseControl = owlBannerControl.find('.pause'); 
                  playControl.on('click', function() {
                  $(this).hide();   $(this).parent().removeClass('active');
                  pauseControl.show();   $this.trigger('play.owl.autoplay', [settings.delay]);
                  $this.owlCarousel('next'); // Manually play next since autoplay waits for delay
                  });
                  
                  pauseControl.on('click', function() {   $(this).hide();
                  $(this).parent().addClass('active');   playControl.show();
                  $this.trigger('stop.owl.autoplay'); });
                  
                  // Number the items in .banner-pager 
                  var dots = $('.banner-pager .banner-control'); dots.each(function(){
                  $(this).find('span').append($(this).index() + 1); });
              });
          }
      }(jQuery));
  
      // Banner Carousel Init
      $("body .carousel-banner").owlBannerCarousel();
      // Init with options: $(".banner-carousel").owlBannerCarousel({delay: 4000,
      // smallSearch:true});
  
      if ($.fn.owlCarousel) {
          // Media Carousel Init
          $(".carousel-media").owlCarousel({
  
              // all these callbacks are to make sure any js inside carousl items can refresh
              // themselves
              onResized: function () {
                  window.setTimeout(function () {
                      $(window).trigger('resize');
                  }, 0)
              },
              onDragged: function () {
                  window.setTimeout(function () {
                      $(window).trigger('resize');
                  }, 0)
              },
              onTranslated: function () {
                  window.setTimeout(function () {
                      $(window).trigger('resize');
                  }, 0)
              },
              responsive: true,
              margin: 10,
              nav: true,
              loop: true,
              responsiveClass: true,
              responsive: {
                  0: {
                      items: 1,
                      nav: true
                  },
                  400: {
                      items: 2
                  },
                  700: {
                      items: 3,
                      nav: true
                  },
                  1000: {
                      items: 4,
                      nav: true
                  }
              },
              navText: [
                  '<span class="ca-gov-icon-arrow-prev" aria-hidden="true"></span>', '<span class="ca-gov-icon-arrow-next" aria-hidden="true"></span>'
              ],
              dots: false
          });
  
          // Link Icon Carousel Init
          $(".carousel-link").owlCarousel({
              margin: 25,
              autoWidth: true,
              nav: true,
              navText: [
                  '<span class="ca-gov-icon-arrow-prev" aria-hidden="true"></span>', '<span class="ca-gov-icon-arrow-next" aria-hidden="true"></span>'
              ],
              dots: false
          });
  
          // Social Media Slider Init
          $(".carousel-slider").owlCarousel({
              items: 1,
              nav: true,
              navText: [
                  '<span class="ca-gov-icon-arrow-prev" aria-hidden="true"></span>', '<span class="ca-gov-icon-arrow-next" aria-hidden="true"></span>'
              ],
              dots: false
          });
  
          // Gallery Image Slider
          $(".carousel-gallery").owlCarousel({
              items: 1,
              nav: true,
              navText: [
                  '<span class="ca-gov-icon-arrow-prev" aria-hidden="true"></span>', '<span class="ca-gov-icon-arrow-next" aria-hidden="true"></span>'
              ],
              dots: false
          });
  
      }
  });
  
  function initContent() {
      var carousel = $(this);
      $(window).on("load", function () {
          carousel.owlCarousel({
              items: 1,
              autoHeight: true,
              loop: true,
              nav: true,
              navText: [
                  '<span class="ca-gov-icon-arrow-prev" aria-hidden="true"></span>', '<span class="ca-gov-icon-arrow-next" aria-hidden="true"></span>'
              ],
              dots: true,
              // all these callbacks are to make sure any js inside carousl items can refresh
              // themselves
              onResized: function () {
                  window.setTimeout(function () {
                      $(window).trigger('resize');
                  }, 0)
              },
              onDragged: function () {
                  window.setTimeout(function () {
                      $(window).trigger('resize');
                  }, 0)
              },
              onTranslated: function () {
                  window.setTimeout(function () {
                      $(window).trigger('resize');
                  }, 0)
              }
          });
          carousel.on('changed.owl.carousel', function (event) {
              setTimeout(function () {
                  carousel.find('.owl-item.active .item video').each(function () {
  
                      $(this).get(0).play();
                  })
              }, 10)
  
          })
      })
  }
  
  (function($) {
  
      $.fn.initCAVideo = function(bool) {
  
  
          // Iterate over each object in collection
          return this.each( function() {
  
              var carousel = $(this);
              var didSet = carousel.attr("data-loaded");
  
              if (didSet) {
                  return;
              }
              carousel.attr("data-loaded", "true");
                  // get first video
                  var vidHref = carousel.find('.item a').first().attr('href') || "";
                  var vidID = vidHref.split("?v=").pop();
  
                  var mainIndex = 0;
  
  
                  var length = carousel.find('.item').length;
  
                  // Video  Slider
                  carousel.owlCarousel({
                      items: 1,
                      loop: false,
                      nav: true,
                      lazyLoad: false,
                      video: true,
                      navText: [
                          '<span class="ca-gov-icon-arrow-prev" aria-hidden="true"></span>', '<span class="ca-gov-icon-arrow-next" aria-hidden="true"></span>'
                      ],
                      dots: false
                  });
  
                  carousel.on('translated.owl.carousel', function(event) {
  
                    // get current video id
                    vidID = carousel.find('.owl-item.active')
                              .attr('data-video').split(/\?v=|\/v\//).pop();
                      setCurrentSubVideo();
  
                    mainIndex = event.item.index;
                      // show the item in view
                      submenu.trigger('to.owl.carousel', [ mainIndex, 300, true ] )
               });
  
  
                  //  create the proper video play icon for each video image preview
                  carousel.find('.owl-video-play-icon').append($('<span class="ca-gov-icon-play" />'));
  
                  // create the overlay for each video image preview
                  carousel.find('.owl-video-tn').after($('<div />').addClass('item-overlay'));
  
                  // the submenu lives as a sibling to the carousel.
                  var submenu = $('<div></div>').insertAfter(carousel);
                  submenu.addClass('carousel owl-carousel carousel-video-submenu');
  
                  // create the sub menu for the videos
                  var items = carousel.find('a.owl-video');
                  items.each(function (index) {
                      // get this slide and its video url
                      var oldItem = $(this);
                      var href = oldItem.attr('href');
  
                      // attach the triggers for each thumbnail
                      var item = $('<div/>').addClass('item-thumbnail');
                      item.on('click', function () {
                          //  force the main carousel to jump to the requested video
                          carousel.trigger('to.owl.carousel', [
                              index  % length,
                              300,
                              true
                          ]);
  
                          submenu.find('.watching').removeClass('watching');
                          $(this).parents('.owl-item').addClass('watching');
  
                          //  start playing immediately
                          carousel.find(".active .owl-video-play-icon").trigger("click");
                      });
  
                      // thumbnail related
                      var regex = new RegExp('ab+c', 'i');
                      var youtubeID = href.split(/\?v=|\/v\//).pop();
                      var youtubeThumb = 'http://img.youtube.com/vi/' + youtubeID + '/0.jpg';
                      var thumbnail = $('<img />').attr('src', youtubeThumb);
  
                      // overlay related
                      var overlay = $('<div />').addClass('item-overlay');
                      overlay.append($('<span class="ca-gov-icon-play" />'))
  
                      // Append it into the DOM
                      item.append(thumbnail).append(overlay);
                      submenu.append(item);
                  });
  
                  submenu = carousel.next();
  
                    submenu.on('initialized.owl.carousel', function() {
                      setCurrentSubVideo();
                    });
  
                  // have owlCarousel init this submenu
                  submenu.owlCarousel({
                      items: 4,
                      loop: false,
                      nav: true,
                      margin: 20,
                      dots: false,
                      navText: ['<span class="ca-gov-icon-arrow-prev" aria-hidden="true"></span>', '<span class="ca-gov-icon-arrow-next" aria-hidden="true"></span>']
                  });
  
  
                submenu.on('changed.owl.carousel', function() {
                  setTimeout(setCurrentSubVideo, 50);
                });
  
                function setCurrentSubVideo() {
                  // remove old watched item
                  submenu.find('.watching').removeClass('watching');
  
                  submenu.find('img[src*="' + vidID + '"]').parents('.owl-item').addClass('watching');
  
  
                }
  
          });
      }
  }(jQuery));
  
  // EQ Heights for Job Wells
  $(document).ready(function() {
     $(".job-detail").eqHeight(".well");
  });
  // EQ Heights for Map & Photo
  $(document).ready(function() {
     $(".location.full").eqHeight(".photo, .map");
  });
  /* -----------------------------------------
     SOCIAL SHARER
     Rewritten using jquery for v5 template
     /source/js/cagov/socialsharer.js
  ----------------------------------------- */
  
  $(document).ready(function(){
      var docTitle = sanitize(document.title);
      var docURL = window.location.href;
      docURL = encodeURIComponent(sanitize(docURL));
  
      // TODO: flickr, linkedin, instagram, pinterest, vimeo, youtube
  
      $(".ca-gov-icon-share-facebook").on('click', function(e) {
        PopupCentered('https://www.facebook.com/sharer/sharer.php?u=' + docURL + '&display=popup','socialsharer','658','450')
      });
  
      $(".ca-gov-icon-share-twitter").on('click', function(e) {
        PopupCentered('https://twitter.com/intent/tweet?text=' + docTitle + '&url=' + docURL,'socialsharer','568','531')
      });
  
      $(".ca-gov-icon-share-googleplus").on('click', function(e) {
        PopupCentered('https://plus.google.com/share?url=' + docURL,'socialsharer','550','552')
      });
  
      $(".ca-gov-icon-share-email").attr('href',  "mailto:?subject=" + docTitle + "&body=%0a" + docURL + "%0a%0a");
  
  function sanitize(sText) {
    // Remove html tags from a string
    var re = /<\S[^>]*>/g;
    sText = sText.replace(re, " ");
    return sText;
  }
  
  
  // Display a popup window centered over the parent window. Works in all browsers
  // except Opera with multiple displays. Opera displays the popup on the primary
  // display only.
  function PopupCentered(url, popupName, popupWidth, popupHeight) {
    // screenX/Y for IE9+ FF Op Chrome, screenLeft/Top for IE7 IE8 Chrome, left/top for old FF
    var parentLeft = window.screenX ? window.screenX : window.screenLeft ? window.screenLeft : screen.left ? screen.left : 0;
    var parentTop = window.screenY ? window.screenY : window.screenTop ? window.screenTop : screen.top ? screen.top : 0;
  
    var parentWidth = window.innerWidth ? window.innerWidth : document.documentElement.clientWidth ? document.documentElement.clientWidth : screen.width;
    var parentHeight = window.innerHeight ? window.innerHeight : document.documentElement.clientHeight ? document.documentElement.clientHeight : screen.height;
  
    var popupLeft = (parentWidth / 2) - (popupWidth / 2) + parentLeft;
    var popupTop = (parentHeight / 2) - (popupHeight / 2) + parentTop;
  
    window.open(url, popupName, 'scrollbars=yes, width=' + popupWidth + ', height=' + popupHeight + ', left=' + popupLeft + ', top=' + popupTop);
  }
  });
  
  /* -----------------------------------------
     BREADCRUMBS - /source/js/cagov/breadcrumb.js
  ----------------------------------------- */
  
  // This function populates the breadcrumb section of the page.
  // Adapted from http://webtools.ca.gov/tools/design-enhancements/breadcrumbs/ to use jQuery
  
  function breadcrumbs()
  {
  	if ( $(".breadcrumb.dynamic")[0] ) { // Make sure browser supports getElementById and breadcrumb_dynamic exists
  		var wrkLocation = location.href;
  		var wrkLength = wrkLocation.indexOf("#");  // Find the begining of any anchor reference
  		if (wrkLength != -1) {
  			wrkLocation = wrkLocation.substr(0,wrkLength);  // Remove the anchor reference
  		}	
  		var wrkLength = wrkLocation.indexOf("?");  // Find the begining of the query string
  		if (wrkLength != -1) {
  			wrkLocation = wrkLocation.substr(0,wrkLength);  // Remove the query string
  		}
  
  		wrkLocation = unescape(wrkLocation);
  
  		//var re = /<\S[^>]*>/g; // Remove html tags from a string
  		var re = /<.*/g; // remove < and anything after
  		wrkLocation = wrkLocation.replace(re, "");
  
  		var arrURL=wrkLocation.split("/"); // Array containing the current location, split at the slashes
  		var output='<li><a href="/">Home</a></li>'; // The string which will be output to the browser, starts with a link to the home page
  		var path = '/'; // Link for the crumbs
  
  		// If last item is blank or index.* or default.*, remove it
  		if (arrURL[arrURL.length-1] == '' || arrURL[arrURL.length-1].match(/^index\.|^default\./i) ) {
  			arrURL.length--;
  		}
  
  		if (arrURL.length > 3) {
  			for (counter = 3;counter < arrURL.length-1;counter++) {  // Loop to display the links
  				path += arrURL[counter] + '/';  // always end links to folder with '/' 
  				output += '<li><a href="' + path + '">' + (arrURL[counter].replace(/(_|-)/g,' ')) + '</a></li>';
  			}
  
  			// Adds a class of active to the current page
  			output += '<li class="active">' + (arrURL[arrURL.length-1].replace(/(_|-)/g,' ').replace(/\.\w{3,5}$/,'')) + '</li>';
  		}
  
  		$(".breadcrumb.dynamic").html(output);  // Display the breadcrumbs
  	}
  }
  
  $(document).ready(function(){
      breadcrumbs();
  });
  
  // End of breadcrumbs javascript
  
  $(document).ready(function () {
      // Create the needed js event listeners, set up classes, etc
      $('.service-group').each(initServiceGroup);
  });
  
  function initServiceGroup() {
  
      // Define variables
      var $service = $(this);
      var $items = $service.find('.service-tile');
  
  
      $service.find('.service-tile-empty').on('click',function(e){
        e.stopPropagation();
        var url =  $(this).attr("data-url");
        window.location = url
      })
  
      $(window).on('resize', function () {
          var newWidth = $(window).width();
          if (newWidth !== cachedWidth) {
              //DO RESIZE HERE
              if (__$currentRow) {
                  shrinkAndRemove(__$currentRow);
              }
              initTiles($service, $items);
  
              cachedWidth = newWidth;
          }
      });
  
      // Mobile scrolling fires a resize event
      // http://stackoverflow.com/questions/9361968/
      // http://stackoverflow.com/questions/17328742
      var cachedWidth = $(window).width();
  
      // need to align all of our tiles from the get go
      $service.eqHeight(".service-tile");
  
      // When we ajax in more content, we have
      // to make sure our heights are still correct, and we have to
      $service.on('more.new', function () {
          $service.eqHeight(".service-tile");
          $(window).trigger('resize');
          $items = $service.find('.service-tile');
          // enable interactions
          initTiles($service, $items);
      })
  
      // make sure any icons are set to the proper size
      $items.find('.icon-fallback').each(setIconFallback);
  
      // enable interactions
      initTiles($service, $items);
      setUpEvents($service);
  
  }
  
  // Our global which holds the currently opened row
  var __$currentRow = null;
  
  function initTiles($service, $items) {
      //  start off with everything closed
      $items.each(function () {
          setCloseClasses($(this));
      });
      // make sure any icons are set to the proper size
      $items.find('.icon-fallback').each(setIconFallback);
      // renable the tabs and accordian plugins
      $items.find('.collapse').collapse();
  
      // remove any inline height set from accordian view
      $service.find('.service-tile-full .container').css({'height': ''})
  }
  
  function shrinkAndRemove($rowEl) {
      // Explicitly set our height so css transitions can work their magic
      // $rowEl.css('height', $rowEl.height() + 'px');
      // we wait for the next redraw so
  
      $rowEl.animate({
          'height': '0px'
      }, 300, 'linear', function () {
          $rowEl.empty().remove();
      })
  
  }
  
  function setUpEvents($service) {
  
      function closeTile(e) {
          var $item = $(this);
          e.preventDefault();
  
          // remove the row
          var $rowEl = findRow($item);
          shrinkAndRemove($rowEl);
  
          // close the tile
          setCloseClasses($item);
  
      }
  
      function openTile(e) {
          var $item = $(this);
          e.preventDefault();
  
          // remove teasers for all others but keep this one
          // update their event handlers
          $service.find('.service-tile').not($item).each(function () {
              var $el = $(this);
              setCloseClasses($el);
          });
  
  
          // set this elements state to open
          $item.attr('data-state', 'open');
  
          // secure the element for holding the content and then insert it
          var $rowEl = findRow($item);
  
          checkIfOldAndSet($rowEl);
  
          insertContent($rowEl, $item);
  
          setCloseButtonEvent($item,closeTile)
  
      }
  
  
      $service.on('click', '.service-tile', function (e) {
          e.preventDefault();
          if ($(this).hasClass("touched")) {
              $(this).removeClass('touched');
              return;
          }
  
          var state = $(this).attr('data-state');
          switch (state) {
              case 'closed':
              case 'info':
                  openTile.call(this, e);
                  // this focues on close button after expandable panel is open, so user can tab into the pannel (it's for accessibility purposes)
                  $("button.close").trigger("focus");
                  break;
              case 'open':
                  closeTile.call(this, e);
                  break;
              default:
          }
      });
  
  
      // add the "tile-focus" class when got focus
      $('.service-tile').on("focusin", function () {
          $(this).addClass("tile-focus");
  
      });
  
  
      // Remove the "tile-focus" class when lost focus
      $('.service-tile').on("focusout", function () {
          $(this).removeClass("tile-focus");
  
      });
  
  
      // Make sure it works on 'enter' key (has same behavior as click event)
      $service.on('keyup', '.service-tile', function (e) {
          if (e.which == 13 && $(".service-tile").hasClass("tile-focus")) {
              $(this).trigger("click");
          }
      });
  
  
  }
  
  // Sets the icons to be big and still fit within the service-tile
  function setIconFallback() {
      var width = $(this).width();
      $(this).css({
          'font-size': width * 0.6
      });
  }
  
  
  // helper which does as it's name implies
  function setCloseClasses($item) {
    $item.attr('data-state', 'closed').removeClass('show-info');
  }
  
  function setCloseButtonEvent($item, func){
    var id = $item.data('tile-id');
  var $content = $item.parent().find('.service-tile-panel[data-tile-id="' + id + '"]').first();
    $content.find('.close.btn').on('click', function(e){
       func.call($item, e);
    })
  }
  
  /**
   * TODO: +Docs
   * TODO: Expand height using calculated content height
   */
  function insertContent($rowEl, $item) {
      if (!$rowEl) {
          return
      }
      var id = $item.data('tile-id');
  
      var $content = $item.parent().find('.service-tile-panel[data-tile-id="' + id + '"]').first();
  
      $rowEl.css('height', $rowEl.height() + "px");
      $rowEl.empty();
      $content.clone().appendTo($rowEl);
      $rowEl.animate({
          'height': $content.height() + 'px'
      }, 300, 'linear', function () {
          $rowEl.css('height', '');
          scrollToEl($item);
      });
  
  }
  
  /**
   * TODO: +Docs
   * @param  {[type]} $item [description]
   * @return {[type]}       [description]
   */
  function findRow($item) {
  
      // look at the following siblings and get the first element which is
      // not on the same row
      var $nextItem = $item.nextAll('.service-tile, .service-tile-full').filter(function () {
          return $(this).offset().top !== $item.offset().top;
      }).first();
  
      // We have already created and inserted the required expanded element
      if ($nextItem.is('.service-tile-full')) {
          // already created the row
          return $nextItem;
      }
  
      // We need to insert a expanded tile here
      if ($nextItem.is('.service-tile')) {
          // we insert the required element and then return after its inserted
          return createExpandedRow($nextItem, 'before');
      }
      if ($item.nextAll('.service-tile').length) {
          return createExpandedRow($item.nextAll('.service-tile').last(), 'after')
      }
      // at this point the only other possiblity is a new row after all siblings
      return createExpandedRow($item, 'after');
  
  }
  
  function checkIfOldAndSet($rowEl) {
      // remove old rows if needed
      if (__$currentRow && !__$currentRow.is($rowEl)) {
          shrinkAndRemove(__$currentRow);
      }
      // set and insert our content
      __$currentRow = $rowEl;
  
  }
  
  /**
   * TODO: +Docs
   * @param  {[type]} $item  [description]
   * @param  {[type]} method [description]
   * @return {[type]}        [description]
   */
  function createExpandedRow($item, method) {
      var newEl = $('<div>').addClass('service-tile-full');
      ($item[method](newEl));
      // HACK: trigger on focus so transitions work
      newEl.trigger("focus");
      newEl.addClass('is-open');
      return newEl;
  }
  
  /* -----------------------------------------
     HELPERS
  ----------------------------------------- */
  
  /**
   * TODO: +Docs
   * @param  {[type]} $el [description]
   * @return {[type]}     [description]
   */
  function scrollToEl($el) {
      if (!$el || !$el.length) {
          return
      }
      var scrollVal = $el.offset().top;
      $('html, body').animate({
          scrollTop: scrollVal
      }, 450);
  }
  
  $(document).ready(function () {
      $('.number-counter').each(initCountUp);
  });
  
  function initCountUp() {
      // our main component
      var counter = $(this);
  
      // get our values the user has configured
      var endCount = counter.text().trim();
  
      // prepare the dom
      counter.text('0');
      counter.css({'visibility': 'visible'});
  
  
  
      // countUp lib options
      var options = {
          "useEasing": true,
          "useGrouping": false,
          "separator": "",
          "decimal": ".",
          "prefix": ""
      };
  
  
      // handle if user has set decimal precision
      var decimals = 0;
      if (endCount.indexOf('.') !== -1) {
          decimals = endCount.split('.')[1].length;
      }
  
      // handle if user has set a comma
      if (endCount.indexOf(',') !== -1) {
          options.useGrouping = true;
          options.separator = ',';
          endCount = parseFloat(endCount.replace(/,/g, ''));
      }
  
      // target, startVal, endVal, decimals, duration, options
      var demo = new CountUp(counter.get(0), 0, endCount, decimals, 3.5, options);
  
      var waypoint = new Waypoint({
          element: counter.get(0),
          // start when it appears at the bottom
          offset: '100%',
          handler: function () {
              demo.start();
          }
      })
  }
  
  
  // polyfill for ie8
  if (!String.prototype.trim) {
    String.prototype.trim = function () {
      return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
    };
  }
  
  /* -----------------------------------------
     HEADER - /source/js/cagov/header.js
  ----------------------------------------- */
  //------------------------------------------------------------- v5 ----------------------------------------- * need to consolidate .header-single-banner with header-large-banner,
  $(document).ready(function () {
      var $headerImage = $('.header-single-banner, .header-large-banner, .header-primary-banner');
  	var $headerLarge = $('.header-large-banner');
  	var $primaryBanner = $('.header-primary-banner');
      var windowHeight = $(window).height();
      var $header = $('header');
  
  
  
      var $askGroup = $('.ask-group');
  
      var $headSearch = $('#head-search');
  
  // Beta 5 Changes please incorporate into source files
  
  setTimeout(function(){
    $askGroup.addClass('in')
    $headSearch.addClass('in')
  }, 150)
  
      // setting up global variables for header functions
      window.headerVars = {
          MOBILEWIDTH: 767,
          MAXHEIGHT: 1200,
          MINHEIGHT: 500,
          setHeaderImageHeight: function () {
              if ($headerImage.length == 0) {
                  return
              }
  			
              var height = windowHeight;
              height = Math.max(Math.min(height, headerVars.MAXHEIGHT), headerVars.MINHEIGHT);
  			
  			var headerTop = $headerImage.offset().top;
  			
              $headerImage.css({'height': height - $header.height()});
              headerImageHeight = $headerImage.height();		
  							
  			$headerLarge.css({'height': height - headerTop});
              headerImageHeight = $headerLarge.height();		
  			
  			$primaryBanner.css({'height': 450 });
  
  // Beta v5 Changes please incorporate into source files	
  
  	
          }
      };
  
      headerVars.setHeaderImageHeight();
  	
  
  
      // Take header image and place it on the ask group div for mobile
  
      var bgImage = $headerImage.css('background-image');
          var askGroup = $('.ask-group');
  
          askGroup.attr("style", "background-size: cover; background-repeat: no-repeat; background-image:" + bgImage)
  
  
  });
  
  /* -----------------------------------------
    FIXED HEADER - /source/js/cagov/fixed-header.js
  ----------------------------------------- */
  $(document).ready(function () {
  
      // The scroll distance (in pixels) which will make the header
      // compact if needed and
      var scrollDistanceToMakeCompactHeader = 220;
      var scrollDistanceToHideSearch = 80;
  
      var askBarPadding = 10;
      // set up variables here for each maintenance in the future.
      var $header = $('header');
      var $headerImage = $('.header-single-banner' );
  
      var $exploreMore = $('.explore-invite');
      var $globalHeader = $('.global-header');
      var $alert = $('.alert-banner');
      var $askGroup = $('.ask-group');
      var $askGroupBar = $('#askGroup');
      var $headSearch = $('#head-search');
      var $mainContent = $('#main-content');
  
      var headerHeight = $globalHeader.innerHeight();
      var windowHeight = $(window).height();
      var windowWidth = $(window).width();
  
      var currentScrollTop = $(document).scrollTop();
  
      var hideDistance = calcInputDifference();
  
      setAskBarTop();
      $headSearch.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function(){ setAskBarTop(); });
      function setAskBarTop() {
          window.setTimeout(function () {
              if ($headSearch.hasClass('active') || !$globalHeader.hasClass('fixed')) {
  
                  return;
              }
  
              if (currentScrollTop >= scrollDistanceToMakeCompactHeader) {
                  return
              }
  
              var searchBox = $headSearch.get(0).getBoundingClientRect();
              var newAskTop = searchBox.top + searchBox.height + askBarPadding;
  
              $askGroupBar.css('top', newAskTop)
              $askGroupBar.trigger('cagov.askgroup.update')
          }, 0)
  
      }
  
      /**
   * Create a return to top button
   */
      var $returnTop = $('<span class="return-top"/>').appendTo('.main-content');
  
      // set up the interaction handlers before anything else
      setResizeHandler();
      setScrollHandler();
  
      /**
       * Since we have a fixed header we need to use js to scroll back to top
       * We also expose it as a jQuery plugin for resuability
       */
      (function ($) {
          $.fn.customScrollTop = function customScrollTop() {
              return this.each(function () {
                  $el = $(this);
                  $el.on('click', function () {
                      $('html,body').animate({
                          scrollTop: 0
                      }, 400, function () {
                          $(window).scroll()
                      });
                      return;
                  })
              });
          }
      }(jQuery));
  
      // Set any buttons or links which must scroll back to the top
      $('[href="#skip-to-content"]').customScrollTop();
  
      $returnTop.customScrollTop();
  
      // we need to jump back up to the top inorder to show the search again
      if ($header.hasClass("fixed")) {
          $('#nav-item-search').customScrollTop();
      }
  
      // fire off the first update to the header, all remaining updates will
      // from user interactions
      updateFixed();
  
      // we need to watch for a user closing the alert banner, as this will
      // change out total header height, forcing us to update our header image
      $alert.on('closed.bs.alert', function () {
          headerHeight = $globalHeader.innerHeight();
          updateFixed();
          setAskBarTop();
      });
  
      /**
     * UTILITY FUNCTIONS
     */
  
      // when the window changes we need to update our variables, and then
      // proactively update our fixed header
      function setResizeHandler() {
          if (!$header.hasClass('fixed')) {
              return
          }
  
          $(window).on('resize', function () {
              windowHeight = $(window).height();
              windowWidth = $(window).width();
              headerHeight = $globalHeader.innerHeight();
              hideDistance = calcInputDifference();
  
              if (windowWidth > headerVars.MOBILEWIDTH) {
                  addFixed();
                  setAskBarTop();
  
              } else {
                  removeFixed();
              }
          setAskBarTop();
          });
      }
  
      function setScrollHandler() {
  
          // function which we will call on scroll.
          // NOTE: keep this minimal to benefit performance.
          var updateFunc;
  
          if ($header.hasClass('fixed')) {
              updateFunc = function () {
  
                  // we dont have any fixed updates if we switch or start in mobile
                  // even if the user has requested to be fixed.
                  if (windowWidth < headerVars.MOBILEWIDTH) {
                      return
                  }
  
                  checkForCompactUpdate();
                  checkForFixedUpdate();
  
              }
          } else {
              updateFunc = function () {
                  checkForReturnTopUpdate();
  
              }
          }
  
          // set up our event listener to update the continously
          // changing variables as well as update
          $(window).on('scroll', function () {
              currentScrollTop = $(document).scrollTop();
              updateFunc();
              checkForReturnTopUpdate();
  
          });
  
          // fire the first update
          updateFunc();
      }
  
      /**
       * Checks to see if we are ready to hide the input and ask bar
       */
      function checkForFixedUpdate() {
          // we dont fade out if we have search results being shown
          if ($headSearch.hasClass('active')) {
              $askGroup.addClass('fixed-hide');
              $header.addClass('compact, .fixed');
  
              return;
          }
  
          // // when we go compact with the header we need to completly hide
          // // our askbar and search. This is due to them being placed relativly
          // // with respect to the header. And as such they get tosed around And
          // // colloide when the header height changes to.
          //  if  ($headSearch.hasClass('compact')) {
          //     $askGroup.addClass('fixed-hide');
          //     $headSearch.addClass('fixed-hide');
          //
          // // not dont hide just yet, still waiting, but we double check and
          // // make sure to remove the fixed-hide class just in case.
          // } else {
          //     $askGroup.removeClass('fixed-hide')
          //     $headSearch.removeClass('fixed-hide')
          // }
      }
  
      // Simply apply the class if we have scrolled the required amount
      function checkForCompactUpdate() {
  
          if (currentScrollTop >= scrollDistanceToHideSearch) {
              $askGroup.addClass('fixed-hide');
              $headSearch.addClass('fixed-hide');
          } else {
              $askGroup.removeClass('fixed-hide')
              $headSearch.removeClass('fixed-hide')
          }
          if (currentScrollTop >= scrollDistanceToMakeCompactHeader) {
              $header.addClass('compact');
  
          } else if ($header.hasClass('compact')) {
              $header.removeClass('compact');
  
          }
  
      }
  
      // Same as the function above, we check if the scroll is far enough to
      // justify showing the return icon
      function checkForReturnTopUpdate() {
          if (currentScrollTop >= scrollDistanceToMakeCompactHeader) {
              $returnTop.addClass('is-visible')
          } else {
              $returnTop.removeClass('is-visible')
          }
      }
  
      /**
       * Figures out the difference between the bottom of the askbar and the
       * explore more bar. Used to caclulate when we should hide these elements
       */
      function calcInputDifference() {
          if (!$exploreMore.length || !$askGroupBar.length) {
              return 0;
          }
  
          return $headSearch.height() + $askGroupBar.height();
          // return $exploreMore.offset().top - $askGroupBar.offset().top +
          //$askGroupBar.height() - 15;
      }
  
      /**
       * Sets and removes the fixed header based upon with and the required class
       */
      function updateFixed() {
          if ($header.hasClass('fixed') && windowWidth > headerVars.MOBILEWIDTH) {
              addFixed();
  
          } else {
              removeFixed();
  
          }
      }
  
      /**
       * Adds the required classes and sets the proper inline styles
       * on the header elements. Also recalculates the header image height
       */
      function addFixed() {
          var leeway = 10;
          $header.addClass('fixed')
          headerVars.setHeaderImageHeight();
  
          // we have a header image, we need to adjust it
          if ($headerImage.length) {
              // take into account the fixed header
              var height = $headerImage.height();
              height = Math.max(Math.min(height, headerVars.MAXHEIGHT), headerVars.MINHEIGHT);
  
              $headerImage.css({
                  height: height + headerHeight + leeway
              });
  // take into account the fixed header -----------------------------------------------------v5 FIX---------------------------------
         	 	
  			}  else {
              // no header image, which means our main content needs to
  		  						
  			$mainContent.css({
                  'padding-top': Math.max(headerHeight, 136)
              })		
  			
  		
  		 	} if ($(".ask-group").length > 0) {
  			$mainContent.addClass('print-p-t'); // Media print .main-content fix	
  			$mainContent.css({
              'padding-top': 0
              })
  			
  			 $('.header-slideshow-banner, .header-primary-banner').css({
  		     'margin-top': 136
  			 
  			 });
  													
  							
          }
      }
   // take into account the fixed header -----------------------------------------------------v5 FIX---------------------------------
   
   
      // remove all inline styles from setting the fixed header
      function removeFixed() {
          $header.removeClass('fixed');
          $headerImage.css({'top': '', 'margin-bottom': ''});
          $mainContent.css({'padding-top': ''});
          $askGroupBar.css('top', '')
      }
  
  });
  $(function () {
      // the half circle dashboard things built with the Donut functions
      $('.stats-highlight').each(initStats);
      $('.plotly-chart').each(initPlotly);
  });
  
  // TODO: fallback image for non-js,
  // Description and details for screen readers
  function initPlotly(d3, Plotly) {
      var container = $(this);
  
      if ($('html').hasClass('ie8') || $('html').hasClass('ie7')) {
          //  TODO: Unsupport graphs fall back to image
          if (!container.has('img').length) {
              container.html('<span class="plotly-chart--loading">Chart image not found</span>')
          }
          return;
      }
  
      // no supplied image fallback show loading indicator
      if (!container.has('img').length) {
          container.html('<span class="plotly-chart--loading">Loading</span>')
      }
  
      var libs = [
          'd3', 'Plotly',
          // for ie9 support
          (('Float32Array' in window)
              ? ''
              : 'typedarray')
      ];
  
      requirejs(libs, function (d3, Plotly) {
          var WIDTH_IN_PERCENT_OF_PARENT = 100,
              HEIGHT_IN_PERCENT_OF_PARENT = 100;
          container.empty();
  
          function getHeight() {
              var tempHeight = container.attr('data-fixed-height')
                  ? container.attr('data-fixed-height') + "px"
                  : HEIGHT_IN_PERCENT_OF_PARENT + "%";
  
              return tempHeight;
          }
          var gd3 = d3.select(container.get(0)).style({
              width: WIDTH_IN_PERCENT_OF_PARENT + '%',
              'margin-left': (100 - WIDTH_IN_PERCENT_OF_PARENT) / 2 + '%',
  
              height: getHeight(),
              'margin-top': (100 - WIDTH_IN_PERCENT_OF_PARENT) / 2 + '%'
          });
  
          var gd = gd3.node();
          var title = container.attr("data-title");
          var xLabel = container.attr('data-x-label');
          var yLabel = container.attr('data-y-label');
  
          getConfig(d3, container, function (config) {
              Plotly.plot(gd, config, {
                  title: title,
                  font: {
                      family: "Source Sans Pro, sans-serif",
                      size: 20,
                      color: '#333'
                  },
                  xaxis: {
                      title: xLabel,
                      titlefont: {
                          family: "Source Sans Pro, sans-serif",
                          size: 18,
                          color: "#333"
                      }
                  },
                  yaxis: {
                      title: yLabel,
                      titlefont: {
                          family: "Source Sans Pro, sans-serif",
                          size: 18,
                          color: "#333"
                      }
                  }
                  // not setting the background color atm, keep default
                  // paper_bgcolor: container.css("background-color")
              });
  
              // This does not work atm,
              // following this issue for updates
              // https://github.com/plotly/plotly.js/issues/102
  
              // container.on('mousemove', function (data) {
              //
              //     // make things bigger
              //     var hovertext = container.find(".hovertext");
              //     var trans = hovertext.attr('transform')
              //     // hovertext.attr('transform', trans + ' scale(1.3)');
              //
              //     // give more padding around text by setting stroke to the
              //     // same color as the fill
              //     var path = hovertext.find('path');
              //     var color = path.css('fill');
              //     console.log(color);
              //     path.css({'stroke-width': 7, 'stroke': color})
              // });
          })
  
          $(window).on('resize', function () {
  
              var gd3 = d3.select(container.get(0)).style({height: getHeight()});
              Plotly.Plots.on("resize", gd);
          });
  
      });
  }
  
  var defaultBar = [
      {
          "type": "bar",
          "x": [],
          "y": [],
          "marker": {
              "color": "#046B99",
              "line": {
                  "width": 0.5
              }
          }
      }
  ];
  
  var defaultLine = [
      {
          "x": [],
          "y": [],
          "mode": "lines",
          "name": "Solid",
          "line": {
              "color": "#046B99",
              "dash": "solid",
              "width": 4
          }
      }
  ];
  
  var defaultPie = [
      {
          "values": [],
          "labels": [],
          "hoverinfo": "label+percent",
          "type": "pie",
          "marker": {
              "colors": [
                  "#E1F2F7",
                  "#9FDBF1",
                  "#02BFE7",
                  "#35BBAA",
                  "#72CE6F",
                  "#815AB4",
                  "#D34A37",
                  "#F27E31",
                  "#FFCA4A"
              ]
          }
      }
  ];
  
  function getConfigSkeleton(type) {
      switch (type) {
          case "bar":
              return defaultBar;
          case "pie":
              return defaultPie;
          case "line":
              return defaultLine;
          default:
              return [];
      }
  }
  
  function getConfig(d3, container, func) {
      var sourceUrl = container.attr('data-datasource-url');
      var configUrl = container.attr('data-config-url');
      var chartType = container.attr('data-type');
      var color = container.attr('data-color');
  
      if (configUrl) {
          $.getJSON(configUrl, func);
          return;
      }
  
      var config = getConfigSkeleton(chartType);
  
      var xValues = container.attr('data-x-values');
      var yValues = container.attr('data-y-values');
  
      if (xValues) {
          xValues = xValues.split('|').map(function (d) {
              if(isNaN(parseFloat(d))) {
                return d;
              }
              return + d
          });
      } else {
          xValues = [];
      }
  
      if (yValues) {
          yValues = yValues.split('|');
      } else {
          yValues = [];
      }
      switch (chartType) {
          case "line":
          case "bar":
              config[0].x = xValues
              config[0].y = yValues.map(function (d) {
                  return + d
              });
              break;
  
          case "pie":
              config[0].values = xValues;
              config[0].labels = yValues;
              break;
          default:
  
      }
  
      if (!color) {
          color = '#046B99';
      }
  
      // specifiying the color
      switch (chartType) {
          case "line":
              config[0].line.color = d3.rgb(color).toString();
              break;
          case "bar":
              config[0].marker.color = d3.rgb(color).toString();
              break;
  
          case "pie":
              var colorA = d3.hsl(color);
              var colorB = d3.hsl((colorA.h - (4 * xValues.length)) % 360, colorA.s, colorA.l)
  
              var colorScale = d3.scale.linear().domain(xValues).interpolate(d3.interpolateHsl).range([colorA.toString(), colorB.toString()]);
              var colors = xValues.map(function (d) {
                  return colorScale(d);
              });
              config[0].marker.colors = colors;
  
              break;
          default:
  
      }
  
      func(config);
  
  }
  
  function initStats() {
      var container = $(this);
      var libs = ['d3'];
      if ($('html').hasClass('ie8')|| $('html').hasClass('ie7') ) {
          return;
          //  TODO: Unsupport graphs fall back to something else
      }
      requirejs(libs, function (d3) {
  
          var shouldFlip = container.attr('data-direction') == 'right'
              ? true
              : false;
  
          var data = parseFloat(container.attr('data-percentfill'));
          var chart = container.find('.half-gauge-chart');
          var color = container.attr('data-colorfill');
          var showHalfTick = container.find('.small-goal-text').length != 0;
  
          var config = {
              bindTo: chart.get(0),
              background: true,
              maxValue: 100,
              startAngle: -90,
              endAngle: 90,
              thickness: 5,
              color: color,
              showHalfTick: showHalfTick,
              size: {
                  width: chart.get(0).clientWidth,
                  height: chart.get(0).clientWidth
              },
              flipStart: shouldFlip
          };
          var Donut = initHalfDonut(d3);
  
          var donutChart = new Donut(config);
  
          donutChart.load({data: 0});
  
          function sizeText() {
              var width = chart.get(0).clientWidth;
              var height = chart.get(0).clientHeight;
              var detail = container.find('.small-goal-text');
              var lineHeight = parseFloat(container.find('.small-goal-text').css('line-height'));
  
              container.find('.info').css({
                  top: -width / 4
              });
              detail.css({
                  'font-size': width / 18
              });
              var detailHeight = detail.height();
  
              detail.css({
                  top: (width < 400)
                      ? detailHeight * 2 + 20
                      : (detailHeight * 1.5)
              })
              container.find('.big-number').css({
                  'font-size': width / 6
              });
              container.find('.percent-detail').css({
                  'font-size': width / 10
              });
          }
  
          sizeText();
  
          $(window).on('resize', function () {
  
              window.setTimeout(function () {
                  config.size = {
                      width: chart.width(),
                      height: chart.width()
                  };
                  config.data = data;
                  donutChart = new Donut(config);
                  donutChart.load({data: data});
                  sizeText();
              }, 10);
  
          });
  
          var waypoint = new Waypoint({
              element: chart.get(0),
              // start when it appears at the bottom
              offset: '100%',
              handler: function () {
                  donutChart.load({data: data})
              }
          });
      })
  
  }
  
  /**
   * Custom Half Donut plugin
   * TODO: code clean up, and refactor
   */
  
  function initHalfDonut(d3) {
  
      var defaults = {
          className: 'donut',
          size: {
              width: 200,
              height: 200
          },
          margin: {
              top: 20,
              right: 20,
              bottom: 20,
              left: 20
          },
          startAngle: 0,
          endAngle: 360,
          thickness: null,
          offset: 0,
          sort: null,
          maxValue: null,
          background: false,
          flipStart: false,
          color: 'rgb(49, 130, 189)',
          accessor: function (d, i) {
              return d;
          }
      };
  
      var Donut = function (config) {
          // need an extend fn
          this.config = extend({}, defaults, config);
  
          // setup radius
          this.config.radius = getRadius(this);
  
          // setup accessor
          this.accessor = this.config.accessor;
  
          // convenience method to map data to start/end angles
          this.pie = d3.layout.pie().sort(this.config.sort).startAngle(degToRad(this.config.startAngle)).endAngle(degToRad(this.config.endAngle))
  
          if (this.accessor && typeof this.accessor === 'function') {
              this.pie.value(this.accessor);
          }
  
          var thickness = getThickness(this);
  
          // setup the arc
          // divide offset by 4 because the middle of the stroke aligns to the edge
          // so it's 1/2 on the outside, 1/2 inside
          this.arc = d3.svg.arc().innerRadius(this.config.radius - thickness - (this.config.offset / 4)).outerRadius(this.config.radius + (this.config.offset / 4));
  
          bindSvgToDom(this);
      };
  
      Donut.prototype.load = function (newOpts) {
          // store data on object
          var data = (newOpts && newOpts.data != null)
              ? newOpts.data
              : this.data.map(this.accessor);
  
          // convert to array if not already
          data = Array.isArray(data)
              ? data
              : [data];
  
          if (this.config.maxValue) {
              this.data = this.pieMaxValue(data);
          } else {
              this.data = this.pie(data);
          }
  
          // drawPaths
          drawPaths(this);
      };
  
      Donut.prototype.pieMaxValue = function (data) {
          var accessor = this.accessor,
              self = this;
  
          // Compute the numeric values for each data element.
          var values = data.map(function (d, i) {
              return + accessor.call(self, d, i);
          });
  
          var sum = d3.sum(values),
              max = d3.max([this.config.maxValue, sum]),
              diff = max - sum;
  
          // Compute the start angle.
          var a = +(degToRad(this.config.startAngle));
  
          // Compute the angular scale factor: from value to radians.
          // include the diff because it will help create angles with a maxValue in mind
          var k = (degToRad(this.config.endAngle) - a) / (sum + diff);
  
          var index = d3.range(data.length);
  
          // Compute the arcs!
          // They are stored in the original data's order.
          var arcs = [];
          index.forEach(function (i) {
              var d;
              arcs[i] = {
                  data: data[i],
                  value: d = values[i],
                  startAngle: a,
                  endAngle: a += d * k
              };
          });
          return arcs;
      };
  
      function getThickness(donut) {
          return donut.config.thickness || donut.config.radius;
      }
  
      /*
       * Setup the svg in the DOM and cache a ref to it
       */
      function bindSvgToDom(donut) {
          var width = getWidth(donut),
              height = getHeight(donut);
          var transString = 'translate(' + width / 2 + ',' + height / 2 + ')' + ((donut.config.flipStart == true)
              ? ' scale(-1,1)'
              : '');
  
          var tempSVG = d3.select(donut.config.bindTo).select('svg');
  
          if (tempSVG.empty()) {
              donut.svg = d3.select(donut.config.bindTo).append('svg').attr('class', donut.config.classNames).attr('width', width).attr('height', height / 2).append('g').attr('transform', transString);
          } else {
              donut.svg = d3.select(donut.config.bindTo).select('svg').attr('class', donut.config.classNames).attr('width', width).attr('height', height / 2).select('g').attr('transform', transString);
              donut.svg.selectAll('*').remove();
          }
  
          if (donut.config.background) {
              donut.svg.append('path').attr('class', 'donut-background').transition().duration(0).attrTween('d', function (d, i) {
                  var fullArc = {
                      value: 0,
                      startAngle: degToRad(donut.config.startAngle),
                      endAngle: degToRad(donut.config.endAngle)
                  };
                  return arcTween.call(this, fullArc, i, donut);
              });
          }
  
          if (donut.config.showHalfTick) {
              donut.svg.append('line').attr('class', 'donut-halfmark').attr('stroke', 'gray').attr('stroke-width', 1).attr({
                  'x1': 0,
                  'x2': 0,
                  'y1': -height / 2 + 10,
                  'y2': -height / 2 + 35
              });
  
          }
      }
  
      function drawPaths(donut) {
          var paths = donut.svg.selectAll('path.donut-section').data(donut.data);
  
          // enter new data
          paths.enter().append('path').attr('class', function (d, i) {
              return 'donut-section value-' + i;
          }).attr('fill', donut.config.color).attr('stroke', '#fff').attr('stroke-width', donut.config.offset / 2);
  
          // transition existing paths
          donut.svg.selectAll('path.donut-section').transition().duration(2000).attrTween('d', function (d, i) {
              return arcTween.call(this, d, i, donut);
          });
  
          // exit old data
          paths.exit().transition().duration(100).attrTween('d', function (d, i) {
              return removeArcTween.call(this, d, i, donut);
          }).remove();
  
      }
  
      // Store the currently-displayed angles in this._current.
      // Then, interpolate from this._current to the new angles.
      function arcTween(a, i, donut) {
          var prevSiblingArc,
              startAngle,
              newArc,
              interpolate;
  
          if (!this._current) {
              prevSiblingArc = donut.svg.selectAll('path')[0][i - 1]; // donut.data[i - 1];
  
              // start at the end of the previous one or start of entire donut
              startAngle = (prevSiblingArc && prevSiblingArc._current)
                  ? prevSiblingArc._current.endAngle
                  : degToRad(donut.config.startAngle);
  
              newArc = {
                  startAngle: startAngle,
                  endAngle: startAngle,
                  value: 0
              };
          }
  
          interpolate = d3.interpolate(this._current || newArc, a);
  
          // cache a copy of data to each path
          this._current = interpolate(0);
          return function (t) {
              return donut.arc(interpolate(t));
          };
      }
  
      function removeArcTween(a, i, donut) {
          var emptyArc = {
                  startAngle: degToRad(donut.config.endAngle),
                  endAngle: degToRad(donut.config.endAngle),
                  value: 0
              },
              i = d3.interpolate(a, emptyArc);
          return function (t) {
              return donut.arc(i(t));
          };
      }
  
      function getRadius(donut) {
          var width = getWidth(donut) - donut.config.margin.left - donut.config.margin.right,
              height = getHeight(donut) - donut.config.margin.top - donut.config.margin.bottom;
  
          return Math.min(width, height) / 2;
      }
  
      function getWidth(donut) {
          return donut.config.size && donut.config.size.width;
      }
  
      function getHeight(donut) {
          return donut.config.size && donut.config.size.height;
      }
  
      function degToRad(degree) {
          return degree * (Math.PI / 180);
      }
  
      function radToDeg(radian) {
          return radian * (180 / Math.PI);
      }
  
      /*
       * Simple extend fn like jQuery
       *
       * Usage: extend({ name: 'Default' }, { name: 'Matt' });
       * Result: { name: 'Matt' }
       */
      function extend() {
          for (var i = 1; i < arguments.length; i++) {
              for (var prop in arguments[i]) {
                  if (arguments[i].hasOwnProperty(prop)) {
                      arguments[0][prop] = arguments[i][prop];
                  }
              }
          }
          return arguments[0];
      }
  
      return Donut;
  
  }
  
  /* -----------------------------------------
     PARALLAX EFFECT
     /source/js/cagov/parallax.js
  ----------------------------------------- */
  
  (function($) {
  
      $.fn.parallax = function(options) {
  
          var windowHeight = $(window).height();
  
          // Establish default settings
          var settings = $.extend({
              speed        : 0.3
          }, options);
  
          // Iterate over each object in collection
          return this.each( function() {
  
              // Save a reference to the element
              var $this = $(this);
  
                // Init proper heights
                var bg_height = ($(window).outerHeight() * settings.speed) + $this.innerHeight();
                $this.css( { 'height' : bg_height } );
  
              // Set up Scroll Handler
              $(window).scroll(function() {
                  var element_top = $this.offset().top,
                      window_top = $(window).scrollTop(),
                      y_pos = ( ( ( window_top + $(window).innerHeight() ) - element_top ) * settings.speed ),
                      main_position;
  
                  main_position = 'translate(0, ' + y_pos + 'px)';
  
                  $this.css( {
                      '-webkit-transform' : main_position,
                      '-moz-transform'    : main_position,
                      '-ms-transform'     : main_position,
                      'transform'         : main_position
                  } );
              });
          // $(window).scroll();
  
          });
      }
  }(jQuery));
  
  $('.parallax-bg').parallax();
  
  /**
   *
   */
  
  $(document).ready(function () {
      $("[class*='animate-']").each(initAnimations);
  });
  
  
  function initAnimations() {
    var $this = $(this);
    var waypoint = new Waypoint({
        element: $this.get(0),
        // start when it appears at the bottom
        offset: '95%',
        handler: function () {
            // get the class and animation name out of it
            var animation = $this.attr("class").match(/animate-(\w+)\b/i)[1];
            var toRemove = 'animate-' + animation;
            var toAdd = 'animated ' + animation;
  
            // update classes
            $this.removeClass('animate-' + animation);
            $this.addClass('animated ' + animation);
  
            // stop firing again
            this.disable();
        }
    })
  }
  
  $(document).ready(function () {
      // apply classes programmatically after user interaction for toggle-more
      //elements
      $('.toggle-more').toggleMore();
  
  
      $('[data-ajax-target]').each(initLoad);
  
      var $viewport = $('html, body');
  
      $(".explore-invite").on('click', function (e) {
          e.preventDefault();
          var extraHeight = $('header.fixed').height();
           $viewport.animate({
              scrollTop: $(".main-primary").offset().top - extraHeight
          }, 2000);
  
          // Stop the animation if the user scrolls
          $(document).one("scroll mousedown DOMMouseScroll mousewheel keyup touchstart", function(e){
              if ( e.which > 0 || e.type === "mousedown" || e.type === "mousewheel"  || e.type == 'touchstart'){
                   $viewport.stop();
              }
          });
      });
  
  
  });
  
  (function($) {
  
      $.fn.toggleMore = function(bool) {
  
        /**
         * Helper for setting required attrs and class
         */
        function expanded($this, bool) {
            if (bool) {
                $this.addClass('active').attr('aria-expanded', 'true');
            } else {
                $this.removeClass('active').attr('aria-expanded', 'false');
            }
        }
  
          // Iterate over each object in collection
          return this.each( function() {
  
              // Save a reference to the element
  
              var $this = $(this);
              if (bool !== undefined) {
                  bool ? expanded($this, true) : expanded($this, false);
  
              } else {
                  // init classes and state
                  $this.hasClass('active')
                      ? expanded($this, true)
                      : expanded($this, false);
              }
  
    
              $this.off("click.cagovmore");
              $this.on("click.cagovmore", function () {
                  $this.hasClass('active')
                      ? expanded($this, false)
                      : expanded($this, true);
              });
  
          });
      }
  }(jQuery));
  
  
  
  
  // TODO: readd this back in
  function makeBlur($el) {
      $el.Vague({intensity: 6}).trigger("blur");
  }
  
  
  function initLoad() {
      var $moreBtn = $(this);
      var htmlURL = $moreBtn.attr('data-ajax-target');
      var elTarget = $moreBtn.attr('data-container-target');
      var moreContents = $moreBtn.find('.more-content');
      var isTest = $moreBtn.attr('data-ajax-test');
      makeBlur(moreContents);
      function loadMore(url) {
          $(moreContents).load(url, function (response, status, xhr) {
            var linkHeader = xhr.getResponseHeader("Link");
            if(isTest) {
              return;
            }
            if ((status == "error" || linkHeader == null)) {
                $moreBtn.animate({
                    'opacity': 0,
                    'height': 0
                }, 300, 'linear');
            } else {
                htmlURL = linkHeader.match(/<(.*?)>/)[1];
            }
        });
      }
  
  
      loadMore(htmlURL);
  
      $moreBtn.on('click', function (e) {
          e.preventDefault();
          $(moreContents).children().hide().appendTo(elTarget).fadeIn(1000)
          $(elTarget).trigger('more.new');
          loadMore(htmlURL);
      })
  }
  
  /* -----------------------------------------
     HIGH CONTRAST MODES
     /source/js/cagov/high-contrast.js
  ----------------------------------------- */
  
  // TODO: Settings stored in cookies
  
  $(document).ready(function () {
  
      //
      // HIGH CONTRAST MODE
      // --------------------------------------------------
  
      var enableHighContrastButton = $('.enableHighContrastMode');
      var disableHighContrastButton = $('.disableHighContrastMode');
      var theHTML = $('html');
  
      var isHighContrast = localStorage.getItem('high-contrast');
  
      function onContrast() {
          enableHighContrastButton.addClass('active');
          disableHighContrastButton.removeClass('active');
          theHTML.addClass('high-contrast');
          localStorage.setItem('high-contrast', 'true');
      }
  
      function OffContrast() {
          disableHighContrastButton.addClass('active');
          enableHighContrastButton.removeClass('active');
          theHTML.removeClass('high-contrast');
          // disable
          localStorage.removeItem('high-contrast');
      }
  
  
      if (isHighContrast) {
          onContrast();
      }
  
      // Enable High Contrast
      enableHighContrastButton.on('click', onContrast);
  
      // Disable High Contrast
      disableHighContrastButton.on('click', OffContrast);
  
      //
      // TEXT ONLY MODE
      // --------------------------------------------------
  
      var enableTextOnlyButton = $('.enableTextOnlyMode');
      var disableTextOnlyButton = $('.disableTextOnlyMode');
  
      // Enable Text Only
      enableTextOnlyButton.on("click", function () {
          enableTextOnlyButton.addClass('active');
          disableTextOnlyButton.removeClass('active');
          $('link[rel~="stylesheet"]').prop('disabled', true);
      });
  
      // Disable Text Only
      disableTextOnlyButton.on("click", function () {
          disableTextOnlyButton.addClass('active');
          enableTextOnlyButton.removeClass('active');
          $('link[rel~="stylesheet"]').prop('disabled', false);
      });
  
      //
      // INCREASE FONT SIZE
      // --------------------------------------------------  TODO: Evaluate the
  
      //accessibility duplication vs using inbuilt browser
      //controls
  
      var incFontSize = $('.increaseTextSize');
      var decFontSize = $('.decreaseTextSize');
      var resetFontSize = $('.resetTextSize');
  
      // in rems's
      var MAXFONTSIZE = 1.5;
      var MINFONTSIZE = 1;
      var STEPVALUE = .1;
  
      // Read in previous settings and convert to number
      var fontSize = +localStorage.getItem('font-size');
      if (fontSize) {
          $('html').css("font-size", fontSize + 'rem')
      } else {
          fontSize = 1;
          $('html').css("font-size", fontSize  + 'rem')
      }
  
      // init button styles for fonts
      updateFontBtns(fontSize);
  
      // utility functions
      function updateFont(f) {
          var updatedSize = Math.min(MAXFONTSIZE, Math.max(f, MINFONTSIZE))
          localStorage.setItem('font-size', updatedSize);
          $('html').css("font-size", updatedSize + "rem");
          updateFontBtns(updatedSize);
          return updatedSize;
      }
  
      function updateFontBtns(f) {
          if (f >= MAXFONTSIZE) {
              // incFontSize.addClass('disabled')
              // decFontSize.removeClass('disabled');
          } else if (f <= MINFONTSIZE) {
              // decFontSize.addClass('disabled')
              // incFontSize.removeClass('disabled');
          } else {
              // incFontSize.removeClass('disabled');
              // decFontSize.removeClass('disabled')
          }
      }
  
      incFontSize.on('click', function () {
          fontSize += STEPVALUE
          fontSize = updateFont(fontSize);
      });
  
      decFontSize.on('click', function () {
          fontSize -= STEPVALUE;
          fontSize = updateFont(fontSize);
      });
  
      resetFontSize.on('click', function () {
          fontSize = updateFont(1)
      })
  });
  
  $(document).ready(function () {
  
  
      var displayCities = $('.located-city-name');
  
      $('.geo-lookup').on('click', function (e) {
          e.preventDefault();
          var currentCookie = getCookie("cagov__geo");
  
          if (currentCookie) {
              displayCities.html('Enter ZIP');
              errorCase();
              return;
          }
  
          if (navigator.geolocation) {
              navigator.geolocation.getCurrentPosition(successFunc, errorCase);
          } else {
              errorCase();
          }
      });
  
      $('.clear-geo').on('click', function (e) {
          e.preventDefault();
  
          if (typeof location.origin === 'undefined')
              location.origin = location.protocol + '//' + location.host;
  
          document.cookie = "cagov__geo=;path=/"
          displayCities.html('Set Location');
          $("#locationSettings").collapse("hide")
      })
  
  
      function errorCase() {
  
          var windowWidth = $(window).width();
          // our mobile breakpoint
          if (windowWidth < 767) {
              $('html, body').animate({
                  scrollTop: 0
              }, 450);
          }
          // Show a zipcode input
          $("#locationSettings").collapse("show")
          var $input = $("#locationSettings").find('input');
          var $btn = $("#locationSettings").find('button');
          // and we prepare our input for user events
          $input.on("keypress", function (e) {
              if (e.which == 13) {
                  lookByZIP.call(this, e);
                  return false; //<---- Add this line
              }
  
          });
  
          $btn.on('click', function (e) {
              e.preventDefault();
  
              lookByZIP.call($input, e);
  
          })
  
      }
  
  
      function lookByZIP(e) {
          var zip = $(this).val();
  
          displayCities.html('Geo Locating...');
  
          var ajax = $.get(window.__getLocation + '?zip=' + zip);
  
          ajax.done(dataSuccess);
  
          ajax.fail(function () {
              displayCities.html('Not Found');
          })
  
      }
  
      function successFunc(pos) {
          var newLoc = {
              lat: pos.coords.latitude,
              lng: pos.coords.longitude,
              time: pos.timestamp
          };
  
          displayCities.html('Geo Locating...');
  
          var ajax = $.get(window.__getLocation + '?lat=' + newLoc.lat + '&lng=' + newLoc.lng)
  
          ajax.done(dataSuccess);
  
          ajax.fail(function () {
              errorCase();
              displayCities.html('Enter ZIP');
          })
  
      }
  
      function dataSuccess(data) {
          var city = data["rows"][0][0];
          //var zipcode = data["rows"][0][1];
          var region = data["rows"][0][2];
  
          window._cagov_newlat = data["rows"][0][3];
          window._cagov_newlng = data["rows"][0][4];
  
  
          $("#locationSettings").collapse("hide");
          displayCities.html(city);
              
         $("[data-locations-landing],[data-locations]").first().loadMapThat();
  
  
          $(".header-single-banner").each(function() {
              var imageAjax = $.get(window.__getImageByLocation);
              imageAjax.done(function(image) {
                  var newBg = 'url("' + image + '")';
                  var oldBg = $(".header-single-banner").css('background-image');
                  if (newBg !== oldBg) {
                      if($(window).width() <= 767) {
                          $(".ask-group").fadeOut('3000', function() {
  
                              $(this).css('background-image', 'url(' + image + ')').fadeIn('3000');
  
  
                          });
                          $(".header-single-banner").css('background-image', 'url(' + image + ')')
                      } else {
                          $(".header-single-banner").fadeOut('3000', function() {
  
                              var bgImg = $(this).css('background-image', 'url(' + image + ')').fadeIn('3000', function(){
                                  $(this).css("display", '');
                              })
  
                          });
  
                          $(".ask-group").css('background-image', 'url(' + image + ')')
                      }
                  }
              });
          });
  
      }
  
      function getCookie(sKey) {
          if (!sKey) {
              return null;
          }
          return decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*([^;]*).*$)|^.*$"), "$1")) || null;
      }
  
  
      function hasCookie(sKey) {
          if (!sKey) {
              return false;
          }
          return (new RegExp("(?:^|;\\s*)" + encodeURIComponent(sKey).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=")).test(document.cookie);
      }
  
  });
  
  /* -----------------------------------------
     ASK GROUP
     /source/js/cagov/ask-group.js
  ----------------------------------------- */
  // Extra override to force the ask bar to maintain its tab index because the bootstrap accesibility plugin
  // adds tab index -1 to collapse components. We arent using the collapse plugin in this manner, so we force the 
  // collapsable items to always be tabbable.
  $('.ask-button').attr('tabindex', 0);
  // Close Ask menu when clicked anwyere outside
  $('body').on('click', function (e) {
  try {
        $('.ask-panel').collapse('hide');
  } catch (e) {
    // ask panel is wonky
  }
  
  });
  