text: /* Zepto 1.2.0 - zepto event ajax form ie detect fx fx_methods assets data deferred callbacks selector touch gesture stack ios3 - zeptojs.com/license */
  (function (global, factory) {
    if (typeof define === 'function' && define.amd) { define(function () { return factory(global) }) } else { factory(global) }
  }(window, function (window) {
    var Zepto = (function () {
      var undefined; var key; var $; var classList; var emptyArray = []; var concat = emptyArray.concat; var filter = emptyArray.filter; var slice = emptyArray.slice
      var document = window.document
      var elementDisplay = {}; var classCache = {}
      var cssNumber = { 'column-count': 1, columns: 1, 'font-weight': 1, 'line-height': 1, opacity: 1, 'z-index': 1, zoom: 1 }
      var fragmentRE = /^\s*<(\w+|!)[^>]*>/
      var singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/
      var tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig
      var rootNodeRE = /^(?:body|html)$/i
      var capitalRE = /([A-Z])/g
  
      // special attributes that should be get/set via method calls
      var methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset']
  
      var adjacencyOperators = ['after', 'prepend', 'before', 'append']
      var table = document.createElement('table')
      var tableRow = document.createElement('tr')
      var containers = {
        tr: document.createElement('tbody'),
        tbody: table,
        thead: table,
        tfoot: table,
        td: tableRow,
        th: tableRow,
        '*': document.createElement('div')
      }
      var simpleSelectorRE = /^[\w-]*$/
      var class2type = {}
      var toString = class2type.toString
      var zepto = {}
      var camelize; var uniq
      var tempParent = document.createElement('div')
      var propMap = {
        tabindex: 'tabIndex',
        readonly: 'readOnly',
        for: 'htmlFor',
        class: 'className',
        maxlength: 'maxLength',
        cellspacing: 'cellSpacing',
        cellpadding: 'cellPadding',
        rowspan: 'rowSpan',
        colspan: 'colSpan',
        usemap: 'useMap',
        frameborder: 'frameBorder',
        contenteditable: 'contentEditable'
      }
      var isArray = Array.isArray ||
        function (object) { return object instanceof Array }
  
      zepto.matches = function (element, selector) {
        if (!selector || !element || element.nodeType !== 1) return false
        var matchesSelector = element.matches || element.webkitMatchesSelector ||
                            element.mozMatchesSelector || element.oMatchesSelector ||
                            element.matchesSelector
        if (matchesSelector) return matchesSelector.call(element, selector)
        // fall back to performing a selector:
        var match; var parent = element.parentNode; var temp = !parent
        if (temp) (parent = tempParent).appendChild(element)
        match = ~zepto.qsa(parent, selector).indexOf(element)
        temp && tempParent.removeChild(element)
        return match
      }
  
      function type (obj) {
        return obj == null ? String(obj)
          : class2type[toString.call(obj)] || 'object'
      }
  
      function isFunction (value) { return type(value) == 'function' }
      function isWindow (obj) { return obj != null && obj == obj.window }
      function isDocument (obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE }
      function isObject (obj) { return type(obj) == 'object' }
      function isPlainObject (obj) {
        return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype
      }
  
      function likeArray (obj) {
        var length = !!obj && 'length' in obj && obj.length
        var type = $.type(obj)
  
        return type != 'function' && !isWindow(obj) && (
          type == 'array' || length === 0 ||
          (typeof length === 'number' && length > 0 && (length - 1) in obj)
        )
      }
  
      function compact (array) { return filter.call(array, function (item) { return item != null }) }
      function flatten (array) { return array.length > 0 ? $.fn.concat.apply([], array) : array }
      camelize = function (str) { return str.replace(/-+(.)?/g, function (match, chr) { return chr ? chr.toUpperCase() : '' }) }
      function dasherize (str) {
        return str.replace(/::/g, '/')
          .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
          .replace(/([a-z\d])([A-Z])/g, '$1_$2')
          .replace(/_/g, '-')
          .toLowerCase()
      }
      uniq = function (array) { return filter.call(array, function (item, idx) { return array.indexOf(item) == idx }) }
  
      function classRE (name) {
        return name in classCache
          ? classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)'))
      }
  
      function maybeAddPx (name, value) {
        return (typeof value === 'number' && !cssNumber[dasherize(name)]) ? value + 'px' : value
      }
  
      function defaultDisplay (nodeName) {
        var element, display
        if (!elementDisplay[nodeName]) {
          element = document.createElement(nodeName)
          document.body.appendChild(element)
          display = getComputedStyle(element, '').getPropertyValue('display')
          element.parentNode.removeChild(element)
          display == 'none' && (display = 'block')
          elementDisplay[nodeName] = display
        }
        return elementDisplay[nodeName]
      }
  
      function children (element) {
        return 'children' in element
          ? slice.call(element.children)
          : $.map(element.childNodes, function (node) { if (node.nodeType == 1) return node })
      }
  
      function Z (dom, selector) {
        var i; var len = dom ? dom.length : 0
        for (i = 0; i < len; i++) this[i] = dom[i]
        this.length = len
        this.selector = selector || ''
      }
  
      // `$.zepto.fragment` takes a html string and an optional tag name
      // to generate DOM nodes from the given html string.
      // The generated DOM nodes are returned as an array.
      // This function can be overridden in plugins for example to make
      // it compatible with browsers that don't support the DOM fully.
      zepto.fragment = function (html, name, properties) {
        var dom, nodes, container
  
        // A special case optimization for a single tag
        if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1))
  
        if (!dom) {
          if (html.replace) html = html.replace(tagExpanderRE, '<$1></$2>')
          if (name === undefined) name = fragmentRE.test(html) && RegExp.$1
          if (!(name in containers)) name = '*'
  
          container = containers[name]
          container.innerHTML = '' + html
          dom = $.each(slice.call(container.childNodes), function () {
            container.removeChild(this)
          })
        }
  
        if (isPlainObject(properties)) {
          nodes = $(dom)
          $.each(properties, function (key, value) {
            if (methodAttributes.indexOf(key) > -1) nodes[key](value)
            else nodes.attr(key, value)
          })
        }
  
        return dom
      }
  
      // `$.zepto.Z` swaps out the prototype of the given `dom` array
      // of nodes with `$.fn` and thus supplying all the Zepto functions
      // to the array. This method can be overridden in plugins.
      zepto.Z = function (dom, selector) {
        return new Z(dom, selector)
      }
  
      // `$.zepto.isZ` should return `true` if the given object is a Zepto
      // collection. This method can be overridden in plugins.
      zepto.isZ = function (object) {
        return object instanceof zepto.Z
      }
  
      // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and
      // takes a CSS selector and an optional context (and handles various
      // special cases).
      // This method can be overridden in plugins.
      zepto.init = function (selector, context) {
        var dom
        // If nothing given, return an empty Zepto collection
        if (!selector) return zepto.Z()
        // Optimize for string selectors
        else if (typeof selector === 'string') {
          selector = selector.trim()
          // If it's a html fragment, create nodes from it
          // Note: In both Chrome 21 and Firefox 15, DOM error 12
          // is thrown if the fragment doesn't begin with <
          if (selector[0] == '<' && fragmentRE.test(selector)) { dom = zepto.fragment(selector, RegExp.$1, context), selector = null }
          // If there's a context, create a collection on that context first, and select
          // nodes from there
          else if (context !== undefined) return $(context).find(selector)
          // If it's a CSS selector, use it to select nodes.
          else dom = zepto.qsa(document, selector)
        }
        // If a function is given, call it when the DOM is ready
        else if (isFunction(selector)) return $(document).ready(selector)
        // If a Zepto collection is given, just return it
        else if (zepto.isZ(selector)) return selector
        else {
        // normalize array if an array of nodes is given
          if (isArray(selector)) dom = compact(selector)
          // Wrap DOM nodes.
          else if (isObject(selector)) { dom = [selector], selector = null }
          // If it's a html fragment, create nodes from it
          else if (fragmentRE.test(selector)) { dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null }
          // If there's a context, create a collection on that context first, and select
          // nodes from there
          else if (context !== undefined) return $(context).find(selector)
          // And last but no least, if it's a CSS selector, use it to select nodes.
          else dom = zepto.qsa(document, selector)
        }
        // create a new Zepto collection from the nodes found
        return zepto.Z(dom, selector)
      }
  
      // `$` will be the base `Zepto` object. When calling this
      // function just call `$.zepto.init, which makes the implementation
      // details of selecting nodes and creating Zepto collections
      // patchable in plugins.
      $ = function (selector, context) {
        return zepto.init(selector, context)
      }
  
      function extend (target, source, deep) {
        for (key in source) {
          if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
            if (isPlainObject(source[key]) && !isPlainObject(target[key])) { target[key] = {} }
            if (isArray(source[key]) && !isArray(target[key])) { target[key] = [] }
            extend(target[key], source[key], deep)
          } else if (source[key] !== undefined) target[key] = source[key]
        }
      }
  
      // Copy all but undefined properties from one or more
      // objects to the `target` object.
      $.extend = function (target) {
        var deep; var args = slice.call(arguments, 1)
        if (typeof target === 'boolean') {
          deep = target
          target = args.shift()
        }
        args.forEach(function (arg) { extend(target, arg, deep) })
        return target
      }
  
      // `$.zepto.qsa` is Zepto's CSS selector implementation which
      // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`.
      // This method can be overridden in plugins.
      zepto.qsa = function (element, selector) {
        var found
        var maybeID = selector[0] == '#'
        var maybeClass = !maybeID && selector[0] == '.'
        var nameOnly = maybeID || maybeClass ? selector.slice(1) : selector // Ensure that a 1 char tag name still gets checked
        var isSimple = simpleSelectorRE.test(nameOnly)
        return (element.getElementById && isSimple && maybeID) // Safari DocumentFragment doesn't have getElementById
          ? ((found = element.getElementById(nameOnly)) ? [found] : [])
          : (element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? []
            : slice.call(
              isSimple && !maybeID && element.getElementsByClassName // DocumentFragment doesn't have getElementsByClassName/TagName
                ? maybeClass ? element.getElementsByClassName(nameOnly) // If it's simple, it could be a class
                  : element.getElementsByTagName(selector) // Or a tag
                : element.querySelectorAll(selector) // Or it's not simple, and we need to query all
            )
      }
  
      function filtered (nodes, selector) {
        return selector == null ? $(nodes) : $(nodes).filter(selector)
      }
  
      $.contains = document.documentElement.contains
        ? function (parent, node) {
          return parent !== node && parent.contains(node)
        }
        : function (parent, node) {
          while (node && (node = node.parentNode)) { if (node === parent) return true }
          return false
        }
  
      function funcArg (context, arg, idx, payload) {
        return isFunction(arg) ? arg.call(context, idx, payload) : arg
      }
  
      function setAttribute (node, name, value) {
        value == null ? node.removeAttribute(name) : node.setAttribute(name, value)
      }
  
      // access className property while respecting SVGAnimatedString
      function className (node, value) {
        var klass = node.className || ''
        var svg = klass && klass.baseVal !== undefined
  
        if (value === undefined) return svg ? klass.baseVal : klass
        svg ? (klass.baseVal = value) : (node.className = value)
      }
  
      // "true"  => true
      // "false" => false
      // "null"  => null
      // "42"    => 42
      // "42.5"  => 42.5
      // "08"    => "08"
      // JSON    => parse if valid
      // String  => self
      function deserializeValue (value) {
        try {
          return value
            ? value == 'true' ||
          (value == 'false' ? false
            : value == 'null' ? null
              : +value + '' == value ? +value
                : /^[\[\{]/.test(value) ? $.parseJSON(value)
                  : value)
            : value
        } catch (e) {
          return value
        }
      }
  
      $.type = type
      $.isFunction = isFunction
      $.isWindow = isWindow
      $.isArray = isArray
      $.isPlainObject = isPlainObject
  
      $.isEmptyObject = function (obj) {
        var name
        for (name in obj) return false
        return true
      }
  
      $.isNumeric = function (val) {
        var num = Number(val); var type = typeof val
        return val != null && type != 'boolean' &&
        (type != 'string' || val.length) &&
        !isNaN(num) && isFinite(num) || false
      }
  
      $.inArray = function (elem, array, i) {
        return emptyArray.indexOf.call(array, elem, i)
      }
  
      $.camelCase = camelize
      $.trim = function (str) {
        return str == null ? '' : String.prototype.trim.call(str)
      }
  
      // plugin compatibility
      $.uuid = 0
      $.support = { }
      $.expr = { }
      $.noop = function () {}
  
      $.map = function (elements, callback) {
        var value; var values = []; var i; var key
        if (likeArray(elements)) {
          for (i = 0; i < elements.length; i++) {
            value = callback(elements[i], i)
            if (value != null) values.push(value)
          }
        } else {
          for (key in elements) {
            value = callback(elements[key], key)
            if (value != null) values.push(value)
          }
        }
        return flatten(values)
      }
  
      $.each = function (elements, callback) {
        var i, key
        if (likeArray(elements)) {
          for (i = 0; i < elements.length; i++) { if (callback.call(elements[i], i, elements[i]) === false) return elements }
        } else {
          for (key in elements) { if (callback.call(elements[key], key, elements[key]) === false) return elements }
        }
  
        return elements
      }
  
      $.grep = function (elements, callback) {
        return filter.call(elements, callback)
      }
  
      if (window.JSON) $.parseJSON = JSON.parse
  
      // Populate the class2type map
      $.each('Boolean Number String Function Array Date RegExp Object Error'.split(' '), function (i, name) {
        class2type['[object ' + name + ']'] = name.toLowerCase()
      })
  
      // Define methods that will be available on all
      // Zepto collections
      $.fn = {
        constructor: zepto.Z,
        length: 0,
  
        // Because a collection acts like an array
        // copy over these useful array functions.
        forEach: emptyArray.forEach,
        reduce: emptyArray.reduce,
        push: emptyArray.push,
        sort: emptyArray.sort,
        splice: emptyArray.splice,
        indexOf: emptyArray.indexOf,
        concat: function () {
          var i; var value; var args = []
          for (i = 0; i < arguments.length; i++) {
            value = arguments[i]
            args[i] = zepto.isZ(value) ? value.toArray() : value
          }
          return concat.apply(zepto.isZ(this) ? this.toArray() : this, args)
        },
  
        // `map` and `slice` in the jQuery API work differently
        // from their array counterparts
        map: function (fn) {
          return $($.map(this, function (el, i) { return fn.call(el, i, el) }))
        },
        slice: function () {
          return $(slice.apply(this, arguments))
        },
  
        ready: function (callback) {
        // don't use "interactive" on IE <= 10 (it can fired premature)
          if (document.readyState === 'complete' ||
            (document.readyState !== 'loading' && !document.documentElement.doScroll)) { setTimeout(function () { callback($) }, 0) } else {
            var handler = function () {
              document.removeEventListener('DOMContentLoaded', handler, false)
              window.removeEventListener('load', handler, false)
              callback($)
            }
            document.addEventListener('DOMContentLoaded', handler, false)
            window.addEventListener('load', handler, false)
          }
          return this
        },
        get: function (idx) {
          return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length]
        },
        toArray: function () { return this.get() },
        size: function () {
          return this.length
        },
        remove: function () {
          return this.each(function () {
            if (this.parentNode != null) { this.parentNode.removeChild(this) }
          })
        },
        each: function (callback) {
          emptyArray.every.call(this, function (el, idx) {
            return callback.call(el, idx, el) !== false
          })
          return this
        },
        filter: function (selector) {
          if (isFunction(selector)) return this.not(this.not(selector))
          return $(filter.call(this, function (element) {
            return zepto.matches(element, selector)
          }))
        },
        add: function (selector, context) {
          return $(uniq(this.concat($(selector, context))))
        },
        is: function (selector) {
          return typeof selector === 'string' ? this.length > 0 && zepto.matches(this[0], selector)
            : selector && this.selector == selector.selector
        },
        not: function (selector) {
          var nodes = []
          if (isFunction(selector) && selector.call !== undefined) {
            this.each(function (idx) {
              if (!selector.call(this, idx)) nodes.push(this)
            })
          } else {
            var excludes = typeof selector === 'string' ? this.filter(selector)
              : (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector)
            this.forEach(function (el) {
              if (excludes.indexOf(el) < 0) nodes.push(el)
            })
          }
          return $(nodes)
        },
        has: function (selector) {
          return this.filter(function () {
            return isObject(selector)
              ? $.contains(this, selector)
              : $(this).find(selector).size()
          })
        },
        eq: function (idx) {
          return idx === -1 ? this.slice(idx) : this.slice(idx, +idx + 1)
        },
        first: function () {
          var el = this[0]
          return el && !isObject(el) ? el : $(el)
        },
        last: function () {
          var el = this[this.length - 1]
          return el && !isObject(el) ? el : $(el)
        },
        find: function (selector) {
          var result; var $this = this
          if (!selector) result = $()
          else if (typeof selector === 'object') {
            result = $(selector).filter(function () {
              var node = this
              return emptyArray.some.call($this, function (parent) {
                return $.contains(parent, node)
              })
            })
          } else if (this.length == 1) result = $(zepto.qsa(this[0], selector))
          else result = this.map(function () { return zepto.qsa(this, selector) })
          return result
        },
        closest: function (selector, context) {
          var nodes = []; var collection = typeof selector === 'object' && $(selector)
          this.each(function (_, node) {
            while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector))) { node = node !== context && !isDocument(node) && node.parentNode }
            if (node && nodes.indexOf(node) < 0) nodes.push(node)
          })
          return $(nodes)
        },
        parents: function (selector) {
          var ancestors = []; var nodes = this
          while (nodes.length > 0) {
            nodes = $.map(nodes, function (node) {
              if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) {
                ancestors.push(node)
                return node
              }
            })
          }
          return filtered(ancestors, selector)
        },
        parent: function (selector) {
          return filtered(uniq(this.pluck('parentNode')), selector)
        },
        children: function (selector) {
          return filtered(this.map(function () { return children(this) }), selector)
        },
        contents: function () {
          return this.map(function () { return this.contentDocument || slice.call(this.childNodes) })
        },
        siblings: function (selector) {
          return filtered(this.map(function (i, el) {
            return filter.call(children(el.parentNode), function (child) { return child !== el })
          }), selector)
        },
        empty: function () {
          return this.each(function () { this.innerHTML = '' })
        },
        // `pluck` is borrowed from Prototype.js
        pluck: function (property) {
          return $.map(this, function (el) { return el[property] })
        },
        show: function () {
          return this.each(function () {
            this.style.display == 'none' && (this.style.display = '')
            if (getComputedStyle(this, '').getPropertyValue('display') == 'none') { this.style.display = defaultDisplay(this.nodeName) }
          })
        },
        replaceWith: function (newContent) {
          return this.before(newContent).remove()
        },
        wrap: function (structure) {
          var func = isFunction(structure)
          if (this[0] && !func) { var dom = $(structure).get(0) }
          var clone = dom.parentNode || this.length > 1
  
          return this.each(function (index) {
            $(this).wrapAll(
              func ? structure.call(this, index)
                : clone ? dom.cloneNode(true) : dom
            )
          })
        },
        wrapAll: function (structure) {
          if (this[0]) {
            $(this[0]).before(structure = $(structure))
            var children
            // drill down to the inmost element
            while ((children = structure.children()).length) structure = children.first()
            $(structure).append(this)
          }
          return this
        },
        wrapInner: function (structure) {
          var func = isFunction(structure)
          return this.each(function (index) {
            var self = $(this); var contents = self.contents()
            var dom = func ? structure.call(this, index) : structure
            contents.length ? contents.wrapAll(dom) : self.append(dom)
          })
        },
        unwrap: function () {
          this.parent().each(function () {
            $(this).replaceWith($(this).children())
          })
          return this
        },
        clone: function () {
          return this.map(function () { return this.cloneNode(true) })
        },
        hide: function () {
          return this.css('display', 'none')
        },
        toggle: function (setting) {
          return this.each(function () {
            var el = $(this)
          ;(setting === undefined ? el.css('display') == 'none' : setting) ? el.show() : el.hide()
          })
        },
        prev: function (selector) { return $(this.pluck('previousElementSibling')).filter(selector || '*') },
        next: function (selector) { return $(this.pluck('nextElementSibling')).filter(selector || '*') },
        html: function (html) {
          return 0 in arguments
            ? this.each(function (idx) {
              var originHtml = this.innerHTML
              $(this).empty().append(funcArg(this, html, idx, originHtml))
            })
            : (0 in this ? this[0].innerHTML : null)
        },
        text: function (text) {
          return 0 in arguments
            ? this.each(function (idx) {
              var newText = funcArg(this, text, idx, this.textContent)
              this.textContent = newText == null ? '' : '' + newText
            })
            : (0 in this ? this.pluck('textContent').join('') : null)
        },
        attr: function (name, value) {
          var result
          return (typeof name === 'string' && !(1 in arguments))
            ? (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined)
            : this.each(function (idx) {
              if (this.nodeType !== 1) return
              if (isObject(name)) for (key in name) setAttribute(this, key, name[key])
              else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name)))
            })
        },
        removeAttr: function (name) {
          return this.each(function () {
            this.nodeType === 1 && name.split(' ').forEach(function (attribute) {
              setAttribute(this, attribute)
            }, this)
          })
        },
        prop: function (name, value) {
          name = propMap[name] || name
          return (typeof name === 'string' && !(1 in arguments))
            ? (this[0] && this[0][name])
            : this.each(function (idx) {
              if (isObject(name)) for (key in name) this[propMap[key] || key] = name[key]
              else this[name] = funcArg(this, value, idx, this[name])
            })
        },
        removeProp: function (name) {
          name = propMap[name] || name
          return this.each(function () { delete this[name] })
        },
        data: function (name, value) {
          var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase()
  
          var data = (1 in arguments)
            ? this.attr(attrName, value)
            : this.attr(attrName)
  
          return data !== null ? deserializeValue(data) : undefined
        },
        val: function (value) {
          if (0 in arguments) {
            if (value == null) value = ''
            return this.each(function (idx) {
              this.value = funcArg(this, value, idx, this.value)
            })
          } else {
            return this[0] && (this[0].multiple
              ? $(this[0]).find('option').filter(function () { return this.selected }).pluck('value')
              : this[0].value)
          }
        },
        offset: function (coordinates) {
          if (coordinates) {
            return this.each(function (index) {
              var $this = $(this)
              var coords = funcArg(this, coordinates, index, $this.offset())
              var parentOffset = $this.offsetParent().offset()
              var props = {
                top: coords.top - parentOffset.top,
                left: coords.left - parentOffset.left
              }
  
              if ($this.css('position') == 'static') props.position = 'relative'
              $this.css(props)
            })
          }
          if (!this.length) return null
          if (document.documentElement !== this[0] && !$.contains(document.documentElement, this[0])) { return { top: 0, left: 0 } }
          var obj = this[0].getBoundingClientRect()
          return {
            left: obj.left + window.pageXOffset,
            top: obj.top + window.pageYOffset,
            width: Math.round(obj.width),
            height: Math.round(obj.height)
          }
        },
        css: function (property, value) {
          if (arguments.length < 2) {
            var element = this[0]
            if (typeof property === 'string') {
              if (!element) return
              return element.style[camelize(property)] || getComputedStyle(element, '').getPropertyValue(property)
            } else if (isArray(property)) {
              if (!element) return
              var props = {}
              var computedStyle = getComputedStyle(element, '')
              $.each(property, function (_, prop) {
                props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop))
              })
              return props
            }
          }
  
          var css = ''
          if (type(property) == 'string') {
            if (!value && value !== 0) { this.each(function () { this.style.removeProperty(dasherize(property)) }) } else { css = dasherize(property) + ':' + maybeAddPx(property, value) }
          } else {
            for (key in property) {
              if (!property[key] && property[key] !== 0) { this.each(function () { this.style.removeProperty(dasherize(key)) }) } else { css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' }
            }
          }
  
          return this.each(function () { this.style.cssText += ';' + css })
        },
        index: function (element) {
          return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0])
        },
        hasClass: function (name) {
          if (!name) return false
          return emptyArray.some.call(this, function (el) {
            return this.test(className(el))
          }, classRE(name))
        },
        addClass: function (name) {
          if (!name) return this
          return this.each(function (idx) {
            if (!('className' in this)) return
            classList = []
            var cls = className(this); var newName = funcArg(this, name, idx, cls)
            newName.split(/\s+/g).forEach(function (klass) {
              if (!$(this).hasClass(klass)) classList.push(klass)
            }, this)
            classList.length && className(this, cls + (cls ? ' ' : '') + classList.join(' '))
          })
        },
        removeClass: function (name) {
          return this.each(function (idx) {
            if (!('className' in this)) return
            if (name === undefined) return className(this, '')
            classList = className(this)
            funcArg(this, name, idx, classList).split(/\s+/g).forEach(function (klass) {
              classList = classList.replace(classRE(klass), ' ')
            })
            className(this, classList.trim())
          })
        },
        toggleClass: function (name, when) {
          if (!name) return this
          return this.each(function (idx) {
            var $this = $(this); var names = funcArg(this, name, idx, className(this))
            names.split(/\s+/g).forEach(function (klass) {
              (when === undefined ? !$this.hasClass(klass) : when)
                ? $this.addClass(klass) : $this.removeClass(klass)
            })
          })
        },
        scrollTop: function (value) {
          if (!this.length) return
          var hasScrollTop = 'scrollTop' in this[0]
          if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset
          return this.each(hasScrollTop
            ? function () { this.scrollTop = value }
            : function () { this.scrollTo(this.scrollX, value) })
        },
        scrollLeft: function (value) {
          if (!this.length) return
          var hasScrollLeft = 'scrollLeft' in this[0]
          if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset
          return this.each(hasScrollLeft
            ? function () { this.scrollLeft = value }
            : function () { this.scrollTo(value, this.scrollY) })
        },
        position: function () {
          if (!this.length) return
  
          var elem = this[0]
          // Get *real* offsetParent
          var offsetParent = this.offsetParent()
          // Get correct offsets
          var offset = this.offset()
          var parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset()
  
          // Subtract element margins
          // note: when an element has margin: auto the offsetLeft and marginLeft
          // are the same in Safari causing offset.left to incorrectly be 0
          offset.top -= parseFloat($(elem).css('margin-top')) || 0
          offset.left -= parseFloat($(elem).css('margin-left')) || 0
  
          // Add offsetParent borders
          parentOffset.top += parseFloat($(offsetParent[0]).css('border-top-width')) || 0
          parentOffset.left += parseFloat($(offsetParent[0]).css('border-left-width')) || 0
  
          // Subtract the two offsets
          return {
            top: offset.top - parentOffset.top,
            left: offset.left - parentOffset.left
          }
        },
        offsetParent: function () {
          return this.map(function () {
            var parent = this.offsetParent || document.body
            while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css('position') == 'static') { parent = parent.offsetParent }
            return parent
          })
        }
      }
  
      // for now
      $.fn.detach = $.fn.remove
  
      // Generate the `width` and `height` functions
      ;['width', 'height'].forEach(function (dimension) {
        var dimensionProperty =
        dimension.replace(/./, function (m) { return m[0].toUpperCase() })
  
        $.fn[dimension] = function (value) {
          var offset; var el = this[0]
          if (value === undefined) {
            return isWindow(el) ? el['inner' + dimensionProperty]
              : isDocument(el) ? el.documentElement['scroll' + dimensionProperty]
                : (offset = this.offset()) && offset[dimension]
          } else {
            return this.each(function (idx) {
              el = $(this)
              el.css(dimension, funcArg(this, value, idx, el[dimension]()))
            })
          }
        }
      })
  
      function traverseNode (node, fun) {
        fun(node)
        for (var i = 0, len = node.childNodes.length; i < len; i++) { traverseNode(node.childNodes[i], fun) }
      }
  
      // Generate the `after`, `prepend`, `before`, `append`,
      // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods.
      adjacencyOperators.forEach(function (operator, operatorIndex) {
        var inside = operatorIndex % 2 //= > prepend, append
  
        $.fn[operator] = function () {
        // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings
          var argType; var nodes = $.map(arguments, function (arg) {
            var arr = []
            argType = type(arg)
            if (argType == 'array') {
              arg.forEach(function (el) {
                if (el.nodeType !== undefined) return arr.push(el)
                else if ($.zepto.isZ(el)) return arr = arr.concat(el.get())
                arr = arr.concat(zepto.fragment(el))
              })
              return arr
            }
            return argType == 'object' || arg == null
              ? arg : zepto.fragment(arg)
          })
          var parent; var copyByClone = this.length > 1
          if (nodes.length < 1) return this
  
          return this.each(function (_, target) {
            parent = inside ? target : target.parentNode
  
            // convert all methods to a "before" operation
            target = operatorIndex == 0 ? target.nextSibling
              : operatorIndex == 1 ? target.firstChild
                : operatorIndex == 2 ? target
                  : null
  
            var parentInDocument = $.contains(document.documentElement, parent)
  
            nodes.forEach(function (node) {
              if (copyByClone) node = node.cloneNode(true)
              else if (!parent) return $(node).remove()
  
              parent.insertBefore(node, target)
              if (parentInDocument) {
                traverseNode(node, function (el) {
                  if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' &&
                 (!el.type || el.type === 'text/javascript') && !el.src) {
                    var target = el.ownerDocument ? el.ownerDocument.defaultView : window
                    target.eval.call(target, el.innerHTML)
                  }
                })
              }
            })
          })
        }
  
        // after    => insertAfter
        // prepend  => prependTo
        // before   => insertBefore
        // append   => appendTo
        $.fn[inside ? operator + 'To' : 'insert' + (operatorIndex ? 'Before' : 'After')] = function (html) {
          $(html)[operator](this)
          return this
        }
      })
  
      zepto.Z.prototype = Z.prototype = $.fn
  
      // Export internal API functions in the `$.zepto` namespace
      zepto.uniq = uniq
      zepto.deserializeValue = deserializeValue
      $.zepto = zepto
  
      return $
    })()
  
    window.Zepto = Zepto
    window.$ === undefined && (window.$ = Zepto)
  
    ;(function ($) {
      var _zid = 1; var undefined
      var slice = Array.prototype.slice
      var isFunction = $.isFunction
      var isString = function (obj) { return typeof obj === 'string' }
      var handlers = {}
      var specialEvents = {}
      var focusinSupported = 'onfocusin' in window
      var focus = { focus: 'focusin', blur: 'focusout' }
      var hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' }
  
      specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents'
  
      function zid (element) {
        return element._zid || (element._zid = _zid++)
      }
      function findHandlers (element, event, fn, selector) {
        event = parse(event)
        if (event.ns) var matcher = matcherFor(event.ns)
        return (handlers[zid(element)] || []).filter(function (handler) {
          return handler &&
          (!event.e || handler.e == event.e) &&
          (!event.ns || matcher.test(handler.ns)) &&
          (!fn || zid(handler.fn) === zid(fn)) &&
          (!selector || handler.sel == selector)
        })
      }
      function parse (event) {
        var parts = ('' + event).split('.')
        return { e: parts[0], ns: parts.slice(1).sort().join(' ') }
      }
      function matcherFor (ns) {
        return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)')
      }
  
      function eventCapture (handler, captureSetting) {
        return handler.del &&
        (!focusinSupported && (handler.e in focus)) ||
        !!captureSetting
      }
  
      function realEvent (type) {
        return hover[type] || (focusinSupported && focus[type]) || type
      }
  
      function add (element, events, fn, data, selector, delegator, capture) {
        var id = zid(element); var set = (handlers[id] || (handlers[id] = []))
        events.split(/\s/).forEach(function (event) {
          if (event == 'ready') return $(document).ready(fn)
          var handler = parse(event)
          handler.fn = fn
          handler.sel = selector
          // emulate mouseenter, mouseleave
          if (handler.e in hover) {
            fn = function (e) {
              var related = e.relatedTarget
              if (!related || (related !== this && !$.contains(this, related))) { return handler.fn.apply(this, arguments) }
            }
          }
          handler.del = delegator
          var callback = delegator || fn
          handler.proxy = function (e) {
            e = compatible(e)
            if (e.isImmediatePropagationStopped()) return
            e.data = data
            var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args))
            if (result === false) e.preventDefault(), e.stopPropagation()
            return result
          }
          handler.i = set.length
          set.push(handler)
          if ('addEventListener' in element) { element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) }
        })
      }
      function remove (element, events, fn, selector, capture) {
        var id = zid(element)
      ;(events || '').split(/\s/).forEach(function (event) {
          findHandlers(element, event, fn, selector).forEach(function (handler) {
            delete handlers[id][handler.i]
            if ('removeEventListener' in element) { element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) }
          })
        })
      }
  
      $.event = { add: add, remove: remove }
  
      $.proxy = function (fn, context) {
        var args = (2 in arguments) && slice.call(arguments, 2)
        if (isFunction(fn)) {
          var proxyFn = function () { return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) }
          proxyFn._zid = zid(fn)
          return proxyFn
        } else if (isString(context)) {
          if (args) {
            args.unshift(fn[context], fn)
            return $.proxy.apply(null, args)
          } else {
            return $.proxy(fn[context], fn)
          }
        } else {
          throw new TypeError('expected function')
        }
      }
  
      $.fn.bind = function (event, data, callback) {
        return this.on(event, data, callback)
      }
      $.fn.unbind = function (event, callback) {
        return this.off(event, callback)
      }
      $.fn.one = function (event, selector, data, callback) {
        return this.on(event, selector, data, callback, 1)
      }
  
      var returnTrue = function () { return true }
      var returnFalse = function () { return false }
      var ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/
      var eventMethods = {
        preventDefault: 'isDefaultPrevented',
        stopImmediatePropagation: 'isImmediatePropagationStopped',
        stopPropagation: 'isPropagationStopped'
      }
  
      function compatible (event, source) {
        if (source || !event.isDefaultPrevented) {
          source || (source = event)
  
          $.each(eventMethods, function (name, predicate) {
            var sourceMethod = source[name]
            event[name] = function () {
              this[predicate] = returnTrue
              return sourceMethod && sourceMethod.apply(source, arguments)
            }
            event[predicate] = returnFalse
          })
  
          try {
            event.timeStamp || (event.timeStamp = Date.now())
          } catch (ignored) { }
  
          if (source.defaultPrevented !== undefined ? source.defaultPrevented
            : 'returnValue' in source ? source.returnValue === false
              : source.getPreventDefault && source.getPreventDefault()) { event.isDefaultPrevented = returnTrue }
        }
        return event
      }
  
      function createProxy (event) {
        var key; var proxy = { originalEvent: event }
        for (key in event) { if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] }
  
        return compatible(proxy, event)
      }
  
      $.fn.delegate = function (selector, event, callback) {
        return this.on(event, selector, callback)
      }
      $.fn.undelegate = function (selector, event, callback) {
        return this.off(event, selector, callback)
      }
  
      $.fn.live = function (event, callback) {
        $(document.body).delegate(this.selector, event, callback)
        return this
      }
      $.fn.die = function (event, callback) {
        $(document.body).undelegate(this.selector, event, callback)
        return this
      }
  
      $.fn.on = function (event, selector, data, callback, one) {
        var autoRemove; var delegator; var $this = this
        if (event && !isString(event)) {
          $.each(event, function (type, fn) {
            $this.on(type, selector, data, fn, one)
          })
          return $this
        }
  
        if (!isString(selector) && !isFunction(callback) && callback !== false) { callback = data, data = selector, selector = undefined }
        if (callback === undefined || data === false) { callback = data, data = undefined }
  
        if (callback === false) callback = returnFalse
  
        return $this.each(function (_, element) {
          if (one) {
            autoRemove = function (e) {
              remove(element, e.type, callback)
              return callback.apply(this, arguments)
            }
          }
  
          if (selector) {
            delegator = function (e) {
              var evt; var match = $(e.target).closest(selector, element).get(0)
              if (match && match !== element) {
                evt = $.extend(createProxy(e), { currentTarget: match, liveFired: element })
                return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1)))
              }
            }
          }
  
          add(element, event, callback, data, selector, delegator || autoRemove)
        })
      }
      $.fn.off = function (event, selector, callback) {
        var $this = this
        if (event && !isString(event)) {
          $.each(event, function (type, fn) {
            $this.off(type, selector, fn)
          })
          return $this
        }
  
        if (!isString(selector) && !isFunction(callback) && callback !== false) { callback = selector, selector = undefined }
  
        if (callback === false) callback = returnFalse
  
        return $this.each(function () {
          remove(this, event, callback, selector)
        })
      }
  
      $.fn.trigger = function (event, args) {
        event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event)
        event._args = args
        return this.each(function () {
        // handle focus(), blur() by calling them directly
          if (event.type in focus && typeof this[event.type] === 'function') this[event.type]()
          // items in the collection might not be DOM elements
          else if ('dispatchEvent' in this) this.dispatchEvent(event)
          else $(this).triggerHandler(event, args)
        })
      }
  
      // triggers event handlers on current element just as if an event occurred,
      // doesn't trigger an actual event, doesn't bubble
      $.fn.triggerHandler = function (event, args) {
        var e, result
        this.each(function (i, element) {
          e = createProxy(isString(event) ? $.Event(event) : event)
          e._args = args
          e.target = element
          $.each(findHandlers(element, event.type || event), function (i, handler) {
            result = handler.proxy(e)
            if (e.isImmediatePropagationStopped()) return false
          })
        })
        return result
      }
  
      // shortcut methods for `.bind(event, fn)` for each event type
      ;('focusin focusout focus blur load resize scroll unload click dblclick ' +
    'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave ' +
    'change select keydown keypress keyup error').split(' ').forEach(function (event) {
        $.fn[event] = function (callback) {
          return (0 in arguments)
            ? this.bind(event, callback)
            : this.trigger(event)
        }
      })
  
      $.Event = function (type, props) {
        if (!isString(type)) props = type, type = props.type
        var event = document.createEvent(specialEvents[type] || 'Events'); var bubbles = true
        if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name])
        event.initEvent(type, bubbles, true)
        return compatible(event)
      }
    })(Zepto)
  
    ;(function ($) {
      var jsonpID = +new Date()
      var document = window.document
      var key
      var name
      var rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi
      var scriptTypeRE = /^(?:text|application)\/javascript/i
      var xmlTypeRE = /^(?:text|application)\/xml/i
      var jsonType = 'application/json'
      var htmlType = 'text/html'
      var blankRE = /^\s*$/
      var originAnchor = document.createElement('a')
  
      originAnchor.href = window.location.href
  
      // trigger a custom event and return false if it was cancelled
      function triggerAndReturn (context, eventName, data) {
        var event = $.Event(eventName)
        $(context).trigger(event, data)
        return !event.isDefaultPrevented()
      }
  
      // trigger an Ajax "global" event
      function triggerGlobal (settings, context, eventName, data) {
        if (settings.global) return triggerAndReturn(context || document, eventName, data)
      }
  
      // Number of active Ajax requests
      $.active = 0
  
      function ajaxStart (settings) {
        if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart')
      }
      function ajaxStop (settings) {
        if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop')
      }
  
      // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable
      function ajaxBeforeSend (xhr, settings) {
        var context = settings.context
        if (settings.beforeSend.call(context, xhr, settings) === false ||
          triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false) { return false }
  
        triggerGlobal(settings, context, 'ajaxSend', [xhr, settings])
      }
      function ajaxSuccess (data, xhr, settings, deferred) {
        var context = settings.context; var status = 'success'
        settings.success.call(context, data, status, xhr)
        if (deferred) deferred.resolveWith(context, [data, status, xhr])
        triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data])
        ajaxComplete(status, xhr, settings)
      }
      // type: "timeout", "error", "abort", "parsererror"
      function ajaxError (error, type, xhr, settings, deferred) {
        var context = settings.context
        settings.error.call(context, xhr, type, error)
        if (deferred) deferred.rejectWith(context, [xhr, type, error])
        triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error || type])
        ajaxComplete(type, xhr, settings)
      }
      // status: "success", "notmodified", "error", "timeout", "abort", "parsererror"
      function ajaxComplete (status, xhr, settings) {
        var context = settings.context
        settings.complete.call(context, xhr, status)
        triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings])
        ajaxStop(settings)
      }
  
      function ajaxDataFilter (data, type, settings) {
        if (settings.dataFilter == empty) return data
        var context = settings.context
        return settings.dataFilter.call(context, data, type)
      }
  
      // Empty function, used as default callback
      function empty () {}
  
      $.ajaxJSONP = function (options, deferred) {
        if (!('type' in options)) return $.ajax(options)
  
        var _callbackName = options.jsonpCallback
        var callbackName = ($.isFunction(_callbackName)
          ? _callbackName() : _callbackName) || ('Zepto' + (jsonpID++))
        var script = document.createElement('script')
        var originalCallback = window[callbackName]
        var responseData
        var abort = function (errorType) {
          $(script).triggerHandler('error', errorType || 'abort')
        }
        var xhr = { abort: abort }; var abortTimeout
  
        if (deferred) deferred.promise(xhr)
  
        $(script).on('load error', function (e, errorType) {
          clearTimeout(abortTimeout)
          $(script).off().remove()
  
          if (e.type == 'error' || !responseData) {
            ajaxError(null, errorType || 'error', xhr, options, deferred)
          } else {
            ajaxSuccess(responseData[0], xhr, options, deferred)
          }
  
          window[callbackName] = originalCallback
          if (responseData && $.isFunction(originalCallback)) { originalCallback(responseData[0]) }
  
          originalCallback = responseData = undefined
        })
  
        if (ajaxBeforeSend(xhr, options) === false) {
          abort('abort')
          return xhr
        }
  
        window[callbackName] = function () {
          responseData = arguments
        }
  
        script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName)
        document.head.appendChild(script)
  
        if (options.timeout > 0) {
          abortTimeout = setTimeout(function () {
            abort('timeout')
          }, options.timeout)
        }
  
        return xhr
      }
  
      $.ajaxSettings = {
      // Default type of request
        type: 'GET',
        // Callback that is executed before request
        beforeSend: empty,
        // Callback that is executed if the request succeeds
        success: empty,
        // Callback that is executed the the server drops error
        error: empty,
        // Callback that is executed on request complete (both: error and success)
        complete: empty,
        // The context for the callbacks
        context: null,
        // Whether to trigger "global" Ajax events
        global: true,
        // Transport
        xhr: function () {
          return new window.XMLHttpRequest()
        },
        // MIME types mapping
        // IIS returns Javascript as "application/x-javascript"
        accepts: {
          script: 'text/javascript, application/javascript, application/x-javascript',
          json: jsonType,
          xml: 'application/xml, text/xml',
          html: htmlType,
          text: 'text/plain'
        },
        // Whether the request is to another domain
        crossDomain: false,
        // Default timeout
        timeout: 0,
        // Whether data should be serialized to string
        processData: true,
        // Whether the browser should be allowed to cache GET responses
        cache: true,
        // Used to handle the raw response data of XMLHttpRequest.
        // This is a pre-filtering function to sanitize the response.
        // The sanitized response should be returned
        dataFilter: empty
      }
  
      function mimeToDataType (mime) {
        if (mime) mime = mime.split(';', 2)[0]
        return mime && (mime == htmlType ? 'html'
          : mime == jsonType ? 'json'
            : scriptTypeRE.test(mime) ? 'script'
              : xmlTypeRE.test(mime) && 'xml') || 'text'
      }
  
      function appendQuery (url, query) {
        if (query == '') return url
        return (url + '&' + query).replace(/[&?]{1,2}/, '?')
      }
  
      // serialize payload and append it to the URL for GET requests
      function serializeData (options) {
        if (options.processData && options.data && $.type(options.data) != 'string') { options.data = $.param(options.data, options.traditional) }
        if (options.data && (!options.type || options.type.toUpperCase() == 'GET' || options.dataType == 'jsonp')) { options.url = appendQuery(options.url, options.data), options.data = undefined }
      }
  
      $.ajax = function (options) {
        var settings = $.extend({}, options || {})
        var deferred = $.Deferred && $.Deferred()
        var urlAnchor; var hashIndex
        for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key]
  
        ajaxStart(settings)
  
        if (!settings.crossDomain) {
          urlAnchor = document.createElement('a')
          urlAnchor.href = settings.url
          // cleans up URL for .href (IE only), see https://github.com/madrobby/zepto/pull/1049
          urlAnchor.href = urlAnchor.href
          settings.crossDomain = (originAnchor.protocol + '//' + originAnchor.host) !== (urlAnchor.protocol + '//' + urlAnchor.host)
        }
  
        if (!settings.url) settings.url = window.location.toString()
        if ((hashIndex = settings.url.indexOf('#')) > -1) settings.url = settings.url.slice(0, hashIndex)
        serializeData(settings)
  
        var dataType = settings.dataType; var hasPlaceholder = /\?.+=\?/.test(settings.url)
        if (hasPlaceholder) dataType = 'jsonp'
  
        if (settings.cache === false || (
          (!options || options.cache !== true) &&
           (dataType == 'script' || dataType == 'jsonp')
        )) { settings.url = appendQuery(settings.url, '_=' + Date.now()) }
  
        if (dataType == 'jsonp') {
          if (!hasPlaceholder) {
            settings.url = appendQuery(settings.url,
              settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?')
          }
          return $.ajaxJSONP(settings, deferred)
        }
  
        var mime = settings.accepts[dataType]
        var headers = { }
        var setHeader = function (name, value) { headers[name.toLowerCase()] = [name, value] }
        var protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol
        var xhr = settings.xhr()
        var nativeSetHeader = xhr.setRequestHeader
        var abortTimeout
  
        if (deferred) deferred.promise(xhr)
  
        if (!settings.crossDomain) setHeader('X-Requested-With', 'XMLHttpRequest')
        setHeader('Accept', mime || '*/*')
        if (mime = settings.mimeType || mime) {
          if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0]
          xhr.overrideMimeType && xhr.overrideMimeType(mime)
        }
        if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) { setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded') }
  
        if (settings.headers) for (name in settings.headers) setHeader(name, settings.headers[name])
        xhr.setRequestHeader = setHeader
  
        xhr.onreadystatechange = function () {
          if (xhr.readyState == 4) {
            xhr.onreadystatechange = empty
            clearTimeout(abortTimeout)
            var result; var error = false
            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) {
              dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type'))
  
              if (xhr.responseType == 'arraybuffer' || xhr.responseType == 'blob') { result = xhr.response } else {
                result = xhr.responseText
  
                try {
                // http://perfectionkills.com/global-eval-what-are-the-options/
                // sanitize response accordingly if data filter callback provided
                  result = ajaxDataFilter(result, dataType, settings)
                  if (dataType == 'script') (1, eval)(result)
                  else if (dataType == 'xml') result = xhr.responseXML
                  else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result)
                } catch (e) { error = e }
  
                if (error) return ajaxError(error, 'parsererror', xhr, settings, deferred)
              }
  
              ajaxSuccess(result, xhr, settings, deferred)
            } else {
              ajaxError(xhr.statusText || null, xhr.status ? 'error' : 'abort', xhr, settings, deferred)
            }
          }
        }
  
        if (ajaxBeforeSend(xhr, settings) === false) {
          xhr.abort()
          ajaxError(null, 'abort', xhr, settings, deferred)
          return xhr
        }
  
        var async = 'async' in settings ? settings.async : true
        xhr.open(settings.type, settings.url, async, settings.username, settings.password)
  
        if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name]
  
        for (name in headers) nativeSetHeader.apply(xhr, headers[name])
  
        if (settings.timeout > 0) {
          abortTimeout = setTimeout(function () {
            xhr.onreadystatechange = empty
            xhr.abort()
            ajaxError(null, 'timeout', xhr, settings, deferred)
          }, settings.timeout)
        }
  
        // avoid sending empty string (#319)
        xhr.send(settings.data ? settings.data : null)
        return xhr
      }
  
      // handle optional data/success arguments
      function parseArguments (url, data, success, dataType) {
        if ($.isFunction(data)) dataType = success, success = data, data = undefined
        if (!$.isFunction(success)) dataType = success, success = undefined
        return {
          url: url,
          data: data,
          success: success,
          dataType: dataType
        }
      }
  
      $.get = function (/* url, data, success, dataType */) {
        return $.ajax(parseArguments.apply(null, arguments))
      }
  
      $.post = function (/* url, data, success, dataType */) {
        var options = parseArguments.apply(null, arguments)
        options.type = 'POST'
        return $.ajax(options)
      }
  
      $.getJSON = function (/* url, data, success */) {
        var options = parseArguments.apply(null, arguments)
        options.dataType = 'json'
        return $.ajax(options)
      }
  
      $.fn.load = function (url, data, success) {
        if (!this.length) return this
        var self = this; var parts = url.split(/\s/); var selector
        var options = parseArguments(url, data, success)
        var callback = options.success
        if (parts.length > 1) options.url = parts[0], selector = parts[1]
        options.success = function (response) {
          self.html(selector
            ? $('<div>').html(response.replace(rscript, '')).find(selector)
            : response)
          callback && callback.apply(self, arguments)
        }
        $.ajax(options)
        return this
      }
  
      var escape = encodeURIComponent
  
      function serialize (params, obj, traditional, scope) {
        var type; var array = $.isArray(obj); var hash = $.isPlainObject(obj)
        $.each(obj, function (key, value) {
          type = $.type(value)
          if (scope) {
            key = traditional ? scope
              : scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']'
          }
          // handle data in serializeArray() format
          if (!scope && array) params.add(value.name, value.value)
          // recurse into nested objects
          else if (type == 'array' || (!traditional && type == 'object')) { serialize(params, value, traditional, key) } else params.add(key, value)
        })
      }
  
      $.param = function (obj, traditional) {
        var params = []
        params.add = function (key, value) {
          if ($.isFunction(value)) value = value()
          if (value == null) value = ''
          this.push(escape(key) + '=' + escape(value))
        }
        serialize(params, obj, traditional)
        return params.join('&').replace(/%20/g, '+')
      }
    })(Zepto)
  
    ;(function ($) {
      $.fn.serializeArray = function () {
        var name; var type; var result = []
        var add = function (value) {
          if (value.forEach) return value.forEach(add)
          result.push({ name: name, value: value })
        }
        if (this[0]) {
          $.each(this[0].elements, function (_, field) {
            type = field.type, name = field.name
            if (name && field.nodeName.toLowerCase() != 'fieldset' &&
          !field.disabled && type != 'submit' && type != 'reset' && type != 'button' && type != 'file' &&
          ((type != 'radio' && type != 'checkbox') || field.checked)) { add($(field).val()) }
          })
        }
        return result
      }
  
      $.fn.serialize = function () {
        var result = []
        this.serializeArray().forEach(function (elm) {
          result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value))
        })
        return result.join('&')
      }
  
      $.fn.submit = function (callback) {
        if (0 in arguments) this.bind('submit', callback)
        else if (this.length) {
          var event = $.Event('submit')
          this.eq(0).trigger(event)
          if (!event.isDefaultPrevented()) this.get(0).submit()
        }
        return this
      }
    })(Zepto)
  
    ;(function () {
    // getComputedStyle shouldn't freak out when called
    // without a valid element as argument
      try {
        getComputedStyle(undefined)
      } catch (e) {
        var nativeGetComputedStyle = getComputedStyle
        window.getComputedStyle = function (element, pseudoElement) {
          try {
            return nativeGetComputedStyle(element, pseudoElement)
          } catch (e) {
            return null
          }
        }
      }
    })()
  
    ;(function ($) {
      function detect (ua, platform) {
        var os = this.os = {}; var browser = this.browser = {}
        var webkit = ua.match(/Web[kK]it[\/]{0,1}([\d.]+)/)
        var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/)
        var osx = !!ua.match(/\(Macintosh\; Intel /)
        var ipad = ua.match(/(iPad).*OS\s([\d_]+)/)
        var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/)
        var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/)
        var webos = ua.match(/(webOS|hpwOS)[\s\/]([\d.]+)/)
        var win = /Win\d{2}|Windows/.test(platform)
        var wp = ua.match(/Windows Phone ([\d.]+)/)
        var touchpad = webos && ua.match(/TouchPad/)
        var kindle = ua.match(/Kindle\/([\d.]+)/)
        var silk = ua.match(/Silk\/([\d._]+)/)
        var blackberry = ua.match(/(BlackBerry).*Version\/([\d.]+)/)
        var bb10 = ua.match(/(BB10).*Version\/([\d.]+)/)
        var rimtabletos = ua.match(/(RIM\sTablet\sOS)\s([\d.]+)/)
        var playbook = ua.match(/PlayBook/)
        var chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/)
        var firefox = ua.match(/Firefox\/([\d.]+)/)
        var firefoxos = ua.match(/\((?:Mobile|Tablet); rv:([\d.]+)\).*Firefox\/[\d.]+/)
        var ie = ua.match(/MSIE\s([\d.]+)/) || ua.match(/Trident\/[\d](?=[^\?]+).*rv:([0-9.].)/)
        var webview = !chrome && ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/)
        var safari = webview || ua.match(/Version\/([\d.]+)([^S](Safari)|[^M]*(Mobile)[^S]*(Safari))/)
  
        // Todo: clean this up with a better OS/browser seperation:
        // - discern (more) between multiple browsers on android
        // - decide if kindle fire in silk mode is android or not
        // - Firefox on Android doesn't specify the Android version
        // - possibly devide in os, device and browser hashes
  
        if (browser.webkit = !!webkit) browser.version = webkit[1]
  
        if (android) os.android = true, os.version = android[2]
        if (iphone && !ipod) os.ios = os.iphone = true, os.version = iphone[2].replace(/_/g, '.')
        if (ipad) os.ios = os.ipad = true, os.version = ipad[2].replace(/_/g, '.')
        if (ipod) os.ios = os.ipod = true, os.version = ipod[3] ? ipod[3].replace(/_/g, '.') : null
        if (wp) os.wp = true, os.version = wp[1]
        if (webos) os.webos = true, os.version = webos[2]
        if (touchpad) os.touchpad = true
        if (blackberry) os.blackberry = true, os.version = blackberry[2]
        if (bb10) os.bb10 = true, os.version = bb10[2]
        if (rimtabletos) os.rimtabletos = true, os.version = rimtabletos[2]
        if (playbook) browser.playbook = true
        if (kindle) os.kindle = true, os.version = kindle[1]
        if (silk) browser.silk = true, browser.version = silk[1]
        if (!silk && os.android && ua.match(/Kindle Fire/)) browser.silk = true
        if (chrome) browser.chrome = true, browser.version = chrome[1]
        if (firefox) browser.firefox = true, browser.version = firefox[1]
        if (firefoxos) os.firefoxos = true, os.version = firefoxos[1]
        if (ie) browser.ie = true, browser.version = ie[1]
        if (safari && (osx || os.ios || win)) {
          browser.safari = true
          if (!os.ios) browser.version = safari[1]
        }
        if (webview) browser.webview = true
  
        os.tablet = !!(ipad || playbook || (android && !ua.match(/Mobile/)) ||
        (firefox && ua.match(/Tablet/)) || (ie && !ua.match(/Phone/) && ua.match(/Touch/)))
        os.phone = !!(!os.tablet && !os.ipod && (android || iphone || webos || blackberry || bb10 ||
        (chrome && ua.match(/Android/)) || (chrome && ua.match(/CriOS\/([\d.]+)/)) ||
        (firefox && ua.match(/Mobile/)) || (ie && ua.match(/Touch/))))
      }
  
      detect.call($, navigator.userAgent, navigator.platform)
      // make available to unit tests
      $.__detect = detect
    })(Zepto)
  
    ;(function ($, undefined) {
      var prefix = ''; var eventPrefix
      var vendors = { Webkit: 'webkit', Moz: '', O: 'o' }
      var testEl = document.createElement('div')
      var supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i
      var transform
      var transitionProperty; var transitionDuration; var transitionTiming; var transitionDelay
      var animationName; var animationDuration; var animationTiming; var animationDelay
      var cssReset = {}
  
      function dasherize (str) { return str.replace(/([A-Z])/g, '-$1').toLowerCase() }
      function normalizeEvent (name) { return eventPrefix ? eventPrefix + name : name.toLowerCase() }
  
      if (testEl.style.transform === undefined) {
        $.each(vendors, function (vendor, event) {
          if (testEl.style[vendor + 'TransitionProperty'] !== undefined) {
            prefix = '-' + vendor.toLowerCase() + '-'
            eventPrefix = event
            return false
          }
        })
      }
  
      transform = prefix + 'transform'
      cssReset[transitionProperty = prefix + 'transition-property'] =
    cssReset[transitionDuration = prefix + 'transition-duration'] =
    cssReset[transitionDelay = prefix + 'transition-delay'] =
    cssReset[transitionTiming = prefix + 'transition-timing-function'] =
    cssReset[animationName = prefix + 'animation-name'] =
    cssReset[animationDuration = prefix + 'animation-duration'] =
    cssReset[animationDelay = prefix + 'animation-delay'] =
    cssReset[animationTiming = prefix + 'animation-timing-function'] = ''
  
      $.fx = {
        off: (eventPrefix === undefined && testEl.style.transitionProperty === undefined),
        speeds: { _default: 400, fast: 200, slow: 600 },
        cssPrefix: prefix,
        transitionEnd: normalizeEvent('TransitionEnd'),
        animationEnd: normalizeEvent('AnimationEnd')
      }
  
      $.fn.animate = function (properties, duration, ease, callback, delay) {
        if ($.isFunction(duration)) { callback = duration, ease = undefined, duration = undefined }
        if ($.isFunction(ease)) { callback = ease, ease = undefined }
        if ($.isPlainObject(duration)) { ease = duration.easing, callback = duration.complete, delay = duration.delay, duration = duration.duration }
        if (duration) {
          duration = (typeof duration === 'number' ? duration
            : ($.fx.speeds[duration] || $.fx.speeds._default)) / 1000
        }
        if (delay) delay = parseFloat(delay) / 1000
        return this.anim(properties, duration, ease, callback, delay)
      }
  
      $.fn.anim = function (properties, duration, ease, callback, delay) {
        var key; var cssValues = {}; var cssProperties; var transforms = ''
        var that = this; var wrappedCallback; var endEvent = $.fx.transitionEnd
        var fired = false
  
        if (duration === undefined) duration = $.fx.speeds._default / 1000
        if (delay === undefined) delay = 0
        if ($.fx.off) duration = 0
  
        if (typeof properties === 'string') {
        // keyframe animation
          cssValues[animationName] = properties
          cssValues[animationDuration] = duration + 's'
          cssValues[animationDelay] = delay + 's'
          cssValues[animationTiming] = (ease || 'linear')
          endEvent = $.fx.animationEnd
        } else {
          cssProperties = []
          // CSS transitions
          for (key in properties) {
            if (supportedTransforms.test(key)) transforms += key + '(' + properties[key] + ') '
            else cssValues[key] = properties[key], cssProperties.push(dasherize(key))
          }
  
          if (transforms) cssValues[transform] = transforms, cssProperties.push(transform)
          if (duration > 0 && typeof properties === 'object') {
            cssValues[transitionProperty] = cssProperties.join(', ')
            cssValues[transitionDuration] = duration + 's'
            cssValues[transitionDelay] = delay + 's'
            cssValues[transitionTiming] = (ease || 'linear')
          }
        }
  
        wrappedCallback = function (event) {
          if (typeof event !== 'undefined') {
            if (event.target !== event.currentTarget) return // makes sure the event didn't bubble from "below"
            $(event.target).unbind(endEvent, wrappedCallback)
          } else { $(this).unbind(endEvent, wrappedCallback) } // triggered by setTimeout
  
          fired = true
          $(this).css(cssReset)
          callback && callback.call(this)
        }
        if (duration > 0) {
          this.bind(endEvent, wrappedCallback)
          // transitionEnd is not always firing on older Android phones
          // so make sure it gets fired
          setTimeout(function () {
            if (fired) return
            wrappedCallback.call(that)
          }, ((duration + delay) * 1000) + 25)
        }
  
        // trigger page reflow so new elements can animate
        this.size() && this.get(0).clientLeft
  
        this.css(cssValues)
  
        if (duration <= 0) {
          setTimeout(function () {
            that.each(function () { wrappedCallback.call(this) })
          }, 0)
        }
  
        return this
      }
  
      testEl = null
    })(Zepto)
  
    ;(function ($, undefined) {
      var document = window.document
      var origShow = $.fn.show; var origHide = $.fn.hide; var origToggle = $.fn.toggle
  
      function anim (el, speed, opacity, scale, callback) {
        if (typeof speed === 'function' && !callback) callback = speed, speed = undefined
        var props = { opacity: opacity }
        if (scale) {
          props.scale = scale
          el.css($.fx.cssPrefix + 'transform-origin', '0 0')
        }
        return el.animate(props, speed, null, callback)
      }
  
      function hide (el, speed, scale, callback) {
        return anim(el, speed, 0, scale, function () {
          origHide.call($(this))
          callback && callback.call(this)
        })
      }
  
      $.fn.show = function (speed, callback) {
        origShow.call(this)
        if (speed === undefined) speed = 0
        else this.css('opacity', 0)
        return anim(this, speed, 1, '1,1', callback)
      }
  
      $.fn.hide = function (speed, callback) {
        if (speed === undefined) return origHide.call(this)
        else return hide(this, speed, '0,0', callback)
      }
  
      $.fn.toggle = function (speed, callback) {
        if (speed === undefined || typeof speed === 'boolean') { return origToggle.call(this, speed) } else {
          return this.each(function () {
            var el = $(this)
            el[el.css('display') == 'none' ? 'show' : 'hide'](speed, callback)
          })
        }
      }
  
      $.fn.fadeTo = function (speed, opacity, callback) {
        return anim(this, speed, opacity, null, callback)
      }
  
      $.fn.fadeIn = function (speed, callback) {
        var target = this.css('opacity')
        if (target > 0) this.css('opacity', 0)
        else target = 1
        return origShow.call(this).fadeTo(speed, target, callback)
      }
  
      $.fn.fadeOut = function (speed, callback) {
        return hide(this, speed, null, callback)
      }
  
      $.fn.fadeToggle = function (speed, callback) {
        return this.each(function () {
          var el = $(this)
          el[
            (el.css('opacity') == 0 || el.css('display') == 'none') ? 'fadeIn' : 'fadeOut'
          ](speed, callback)
        })
      }
    })(Zepto)
  
    ;(function ($) {
      var cache = []; var timeout
  
      $.fn.remove = function () {
        return this.each(function () {
          if (this.parentNode) {
            if (this.tagName === 'IMG') {
              cache.push(this)
              this.src = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
              if (timeout) clearTimeout(timeout)
              timeout = setTimeout(function () { cache = [] }, 60000)
            }
            this.parentNode.removeChild(this)
          }
        })
      }
    })(Zepto)
  
    ;(function ($) {
      var data = {}; var dataAttr = $.fn.data; var camelize = $.camelCase
      var exp = $.expando = 'Zepto' + (+new Date()); var emptyArray = []
  
      // Get value from node:
      // 1. first try key as given,
      // 2. then try camelized key,
      // 3. fall back to reading "data-*" attribute.
      function getData (node, name) {
        var id = node[exp]; var store = id && data[id]
        if (name === undefined) return store || setData(node)
        else {
          if (store) {
            if (name in store) return store[name]
            var camelName = camelize(name)
            if (camelName in store) return store[camelName]
          }
          return dataAttr.call($(node), name)
        }
      }
  
      // Store value under camelized key on node
      function setData (node, name, value) {
        var id = node[exp] || (node[exp] = ++$.uuid)
        var store = data[id] || (data[id] = attributeData(node))
        if (name !== undefined) store[camelize(name)] = value
        return store
      }
  
      // Read all "data-*" attributes from a node
      function attributeData (node) {
        var store = {}
        $.each(node.attributes || emptyArray, function (i, attr) {
          if (attr.name.indexOf('data-') == 0) {
            store[camelize(attr.name.replace('data-', ''))] =
            $.zepto.deserializeValue(attr.value)
          }
        })
        return store
      }
  
      $.fn.data = function (name, value) {
        return value === undefined
        // set multiple values via object
          ? $.isPlainObject(name)
            ? this.each(function (i, node) {
              $.each(name, function (key, value) { setData(node, key, value) })
            })
          // get value from first element
            : (0 in this ? getData(this[0], name) : undefined)
        // set value on all elements
          : this.each(function () { setData(this, name, value) })
      }
  
      $.data = function (elem, name, value) {
        return $(elem).data(name, value)
      }
  
      $.hasData = function (elem) {
        var id = elem[exp]; var store = id && data[id]
        return store ? !$.isEmptyObject(store) : false
      }
  
      $.fn.removeData = function (names) {
        if (typeof names === 'string') names = names.split(/\s+/)
        return this.each(function () {
          var id = this[exp]; var store = id && data[id]
          if (store) {
            $.each(names || store, function (key) {
              delete store[names ? camelize(this) : key]
            })
          }
        })
      }
  
      // Generate extended `remove` and `empty` functions
      ;['remove', 'empty'].forEach(function (methodName) {
        var origFn = $.fn[methodName]
        $.fn[methodName] = function () {
          var elements = this.find('*')
          if (methodName === 'remove') elements = elements.add(this)
          elements.removeData()
          return origFn.call(this)
        }
      })
    })(Zepto)
  
    ;(function ($) {
      var slice = Array.prototype.slice
  
      function Deferred (func) {
        var tuples = [
          // action, add listener, listener list, final state
          ['resolve', 'done', $.Callbacks({ once: 1, memory: 1 }), 'resolved'],
          ['reject', 'fail', $.Callbacks({ once: 1, memory: 1 }), 'rejected'],
          ['notify', 'progress', $.Callbacks({ memory: 1 })]
        ]
        var state = 'pending'
        var promise = {
          state: function () {
            return state
          },
          always: function () {
            deferred.done(arguments).fail(arguments)
            return this
          },
          then: function (/* fnDone [, fnFailed [, fnProgress]] */) {
            var fns = arguments
            return Deferred(function (defer) {
              $.each(tuples, function (i, tuple) {
                var fn = $.isFunction(fns[i]) && fns[i]
                deferred[tuple[1]](function () {
                  var returned = fn && fn.apply(this, arguments)
                  if (returned && $.isFunction(returned.promise)) {
                    returned.promise()
                      .done(defer.resolve)
                      .fail(defer.reject)
                      .progress(defer.notify)
                  } else {
                    var context = this === promise ? defer.promise() : this
                    var values = fn ? [returned] : arguments
                    defer[tuple[0] + 'With'](context, values)
                  }
                })
              })
              fns = null
            }).promise()
          },
  
          promise: function (obj) {
            return obj != null ? $.extend(obj, promise) : promise
          }
        }
        var deferred = {}
  
        $.each(tuples, function (i, tuple) {
          var list = tuple[2]
          var stateString = tuple[3]
  
          promise[tuple[1]] = list.add
  
          if (stateString) {
            list.add(function () {
              state = stateString
            }, tuples[i ^ 1][2].disable, tuples[2][2].lock)
          }
  
          deferred[tuple[0]] = function () {
            deferred[tuple[0] + 'With'](this === deferred ? promise : this, arguments)
            return this
          }
          deferred[tuple[0] + 'With'] = list.fireWith
        })
  
        promise.promise(deferred)
        if (func) func.call(deferred, deferred)
        return deferred
      }
  
      $.when = function (sub) {
        var resolveValues = slice.call(arguments)
        var len = resolveValues.length
        var i = 0
        var remain = len !== 1 || (sub && $.isFunction(sub.promise)) ? len : 0
        var deferred = remain === 1 ? sub : Deferred()
        var progressValues; var progressContexts; var resolveContexts
        var updateFn = function (i, ctx, val) {
          return function (value) {
            ctx[i] = this
            val[i] = arguments.length > 1 ? slice.call(arguments) : value
            if (val === progressValues) {
              deferred.notifyWith(ctx, val)
            } else if (!(--remain)) {
              deferred.resolveWith(ctx, val)
            }
          }
        }
  
        if (len > 1) {
          progressValues = new Array(len)
          progressContexts = new Array(len)
          resolveContexts = new Array(len)
          for (; i < len; ++i) {
            if (resolveValues[i] && $.isFunction(resolveValues[i].promise)) {
              resolveValues[i].promise()
                .done(updateFn(i, resolveContexts, resolveValues))
                .fail(deferred.reject)
                .progress(updateFn(i, progressContexts, progressValues))
            } else {
              --remain
            }
          }
        }
        if (!remain) deferred.resolveWith(resolveContexts, resolveValues)
        return deferred.promise()
      }
  
      $.Deferred = Deferred
    })(Zepto)
  
    ;(function ($) {
    // Create a collection of callbacks to be fired in a sequence, with configurable behaviour
    // Option flags:
    //   - once: Callbacks fired at most one time.
    //   - memory: Remember the most recent context and arguments
    //   - stopOnFalse: Cease iterating over callback list
    //   - unique: Permit adding at most one instance of the same callback
      $.Callbacks = function (options) {
        options = $.extend({}, options)
  
        var memory // Last fire value (for non-forgettable lists)
        var fired // Flag to know if list was already fired
        var firing // Flag to know if list is currently firing
        var firingStart // First callback to fire (used internally by add and fireWith)
        var firingLength // End of the loop when firing
        var firingIndex // Index of currently firing callback (modified by remove if needed)
        var list = [] // Actual callback list
        var stack = !options.once && [] // Stack of fire calls for repeatable lists
        var fire = function (data) {
          memory = options.memory && data
          fired = true
          firingIndex = firingStart || 0
          firingStart = 0
          firingLength = list.length
          firing = true
          for (; list && firingIndex < firingLength; ++firingIndex) {
            if (list[firingIndex].apply(data[0], data[1]) === false && options.stopOnFalse) {
              memory = false
              break
            }
          }
          firing = false
          if (list) {
            if (stack) stack.length && fire(stack.shift())
            else if (memory) list.length = 0
            else Callbacks.disable()
          }
        }
  
        var Callbacks = {
          add: function () {
            if (list) {
              var start = list.length
              var add = function (args) {
                $.each(args, function (_, arg) {
                  if (typeof arg === 'function') {
                    if (!options.unique || !Callbacks.has(arg)) list.push(arg)
                  } else if (arg && arg.length && typeof arg !== 'string') add(arg)
                })
              }
              add(arguments)
              if (firing) firingLength = list.length
              else if (memory) {
                firingStart = start
                fire(memory)
              }
            }
            return this
          },
          remove: function () {
            if (list) {
              $.each(arguments, function (_, arg) {
                var index
                while ((index = $.inArray(arg, list, index)) > -1) {
                  list.splice(index, 1)
                  // Handle firing indexes
                  if (firing) {
                    if (index <= firingLength) --firingLength
                    if (index <= firingIndex) --firingIndex
                  }
                }
              })
            }
            return this
          },
          has: function (fn) {
            return !!(list && (fn ? $.inArray(fn, list) > -1 : list.length))
          },
          empty: function () {
            firingLength = list.length = 0
            return this
          },
          disable: function () {
            list = stack = memory = undefined
            return this
          },
          disabled: function () {
            return !list
          },
          lock: function () {
            stack = undefined
            if (!memory) Callbacks.disable()
            return this
          },
          locked: function () {
            return !stack
          },
          fireWith: function (context, args) {
            if (list && (!fired || stack)) {
              args = args || []
              args = [context, args.slice ? args.slice() : args]
              if (firing) stack.push(args)
              else fire(args)
            }
            return this
          },
          fire: function () {
            return Callbacks.fireWith(this, arguments)
          },
          fired: function () {
            return !!fired
          }
        }
  
        return Callbacks
      }
    })(Zepto)
  
    ;(function ($) {
      var zepto = $.zepto; var oldQsa = zepto.qsa; var oldMatches = zepto.matches
  
      function visible (elem) {
        elem = $(elem)
        return !!(elem.width() || elem.height()) && elem.css('display') !== 'none'
      }
  
      // Implements a subset from:
      // http://api.jquery.com/category/selectors/jquery-selector-extensions/
      //
      // Each filter function receives the current index, all nodes in the
      // considered set, and a value if there were parentheses. The value
      // of `this` is the node currently being considered. The function returns the
      // resulting node(s), null, or undefined.
      //
      // Complex selectors are not supported:
      //   li:has(label:contains("foo")) + li:has(label:contains("bar"))
      //   ul.inner:first > li
      var filters = $.expr[':'] = {
        visible: function () { if (visible(this)) return this },
        hidden: function () { if (!visible(this)) return this },
        selected: function () { if (this.selected) return this },
        checked: function () { if (this.checked) return this },
        parent: function () { return this.parentNode },
        first: function (idx) { if (idx === 0) return this },
        last: function (idx, nodes) { if (idx === nodes.length - 1) return this },
        eq: function (idx, _, value) { if (idx === value) return this },
        contains: function (idx, _, text) { if ($(this).text().indexOf(text) > -1) return this },
        has: function (idx, _, sel) { if (zepto.qsa(this, sel).length) return this }
      }
  
      var filterRe = new RegExp('(.*):(\\w+)(?:\\(([^)]+)\\))?$\\s*')
      var childRe = /^\s*>/
      var classTag = 'Zepto' + (+new Date())
  
      function process (sel, fn) {
      // quote the hash in `a[href^=#]` expression
        sel = sel.replace(/=#\]/g, '="#"]')
        var filter; var arg; var match = filterRe.exec(sel)
        if (match && match[2] in filters) {
          filter = filters[match[2]], arg = match[3]
          sel = match[1]
          if (arg) {
            var num = Number(arg)
            if (isNaN(num)) arg = arg.replace(/^["']|["']$/g, '')
            else arg = num
          }
        }
        return fn(sel, filter, arg)
      }
  
      zepto.qsa = function (node, selector) {
        return process(selector, function (sel, filter, arg) {
          try {
            var taggedParent
            if (!sel && filter) sel = '*'
            else if (childRe.test(sel))
            // support "> *" child queries by tagging the parent node with a
            // unique class and prepending that classname onto the selector
            { taggedParent = $(node).addClass(classTag), sel = '.' + classTag + ' ' + sel }
  
            var nodes = oldQsa(node, sel)
          } catch (e) {
            console.error('error performing selector: %o', selector)
            throw e
          } finally {
            if (taggedParent) taggedParent.removeClass(classTag)
          }
          return !filter ? nodes
            : zepto.uniq($.map(nodes, function (n, i) { return filter.call(n, i, nodes, arg) }))
        })
      }
  
      zepto.matches = function (node, selector) {
        return process(selector, function (sel, filter, arg) {
          return (!sel || oldMatches(node, sel)) &&
          (!filter || filter.call(node, null, arg) === node)
        })
      }
    })(Zepto)
  
    ;(function ($) {
      var touch = {}
      var touchTimeout; var tapTimeout; var swipeTimeout; var longTapTimeout
      var longTapDelay = 750
      var gesture
      var down; var up; var move
      var eventMap
      var initialized = false
  
      function swipeDirection (x1, x2, y1, y2) {
        return Math.abs(x1 - x2) >=
        Math.abs(y1 - y2) ? (x1 - x2 > 0 ? 'Left' : 'Right') : (y1 - y2 > 0 ? 'Up' : 'Down')
      }
  
      function longTap () {
        longTapTimeout = null
        if (touch.last) {
          touch.el.trigger('longTap')
          touch = {}
        }
      }
  
      function cancelLongTap () {
        if (longTapTimeout) clearTimeout(longTapTimeout)
        longTapTimeout = null
      }
  
      function cancelAll () {
        if (touchTimeout) clearTimeout(touchTimeout)
        if (tapTimeout) clearTimeout(tapTimeout)
        if (swipeTimeout) clearTimeout(swipeTimeout)
        if (longTapTimeout) clearTimeout(longTapTimeout)
        touchTimeout = tapTimeout = swipeTimeout = longTapTimeout = null
        touch = {}
      }
  
      function isPrimaryTouch (event) {
        return (event.pointerType == 'touch' ||
        event.pointerType == event.MSPOINTER_TYPE_TOUCH) &&
        event.isPrimary
      }
  
      function isPointerEventType (e, type) {
        return (e.type == 'pointer' + type ||
        e.type.toLowerCase() == 'mspointer' + type)
      }
  
      // helper function for tests, so they check for different APIs
      function unregisterTouchEvents () {
        if (!initialized) return
        $(document).off(eventMap.down, down)
          .off(eventMap.up, up)
          .off(eventMap.move, move)
          .off(eventMap.cancel, cancelAll)
        $(window).off('scroll', cancelAll)
        cancelAll()
        initialized = false
      }
  
      function setup (__eventMap) {
        var now; var delta; var deltaX = 0; var deltaY = 0; var firstTouch; var _isPointerType
  
        unregisterTouchEvents()
  
        eventMap = (__eventMap && ('down' in __eventMap)) ? __eventMap
          : ('ontouchstart' in document
            ? {
              down: 'touchstart',
              up: 'touchend',
              move: 'touchmove',
              cancel: 'touchcancel'
            }
            : 'onpointerdown' in document
              ? {
                down: 'pointerdown',
                up: 'pointerup',
                move: 'pointermove',
                cancel: 'pointercancel'
              }
              : 'onmspointerdown' in document
                ? {
                  down: 'MSPointerDown',
                  up: 'MSPointerUp',
                  move: 'MSPointerMove',
                  cancel: 'MSPointerCancel'
                } : false)
  
        // No API availables for touch events
        if (!eventMap) return
  
        if ('MSGesture' in window) {
          gesture = new MSGesture()
          gesture.target = document.body
  
          $(document)
            .bind('MSGestureEnd', function (e) {
              var swipeDirectionFromVelocity =
              e.velocityX > 1 ? 'Right' : e.velocityX < -1 ? 'Left' : e.velocityY > 1 ? 'Down' : e.velocityY < -1 ? 'Up' : null
              if (swipeDirectionFromVelocity) {
                touch.el.trigger('swipe')
                touch.el.trigger('swipe' + swipeDirectionFromVelocity)
              }
            })
        }
  
        down = function (e) {
          if ((_isPointerType = isPointerEventType(e, 'down')) &&
          !isPrimaryTouch(e)) return
          firstTouch = _isPointerType ? e : e.touches[0]
          if (e.touches && e.touches.length === 1 && touch.x2) {
          // Clear out touch movement data if we have it sticking around
          // This can occur if touchcancel doesn't fire due to preventDefault, etc.
            touch.x2 = undefined
            touch.y2 = undefined
          }
          now = Date.now()
          delta = now - (touch.last || now)
          touch.el = $('tagName' in firstTouch.target
            ? firstTouch.target : firstTouch.target.parentNode)
          touchTimeout && clearTimeout(touchTimeout)
          touch.x1 = firstTouch.pageX
          touch.y1 = firstTouch.pageY
          if (delta > 0 && delta <= 250) touch.isDoubleTap = true
          touch.last = now
          longTapTimeout = setTimeout(longTap, longTapDelay)
          // adds the current touch contact for IE gesture recognition
          if (gesture && _isPointerType) gesture.addPointer(e.pointerId)
        }
  
        move = function (e) {
          if ((_isPointerType = isPointerEventType(e, 'move')) &&
          !isPrimaryTouch(e)) return
          firstTouch = _isPointerType ? e : e.touches[0]
          cancelLongTap()
          touch.x2 = firstTouch.pageX
          touch.y2 = firstTouch.pageY
  
          deltaX += Math.abs(touch.x1 - touch.x2)
          deltaY += Math.abs(touch.y1 - touch.y2)
        }
  
        up = function (e) {
          if ((_isPointerType = isPointerEventType(e, 'up')) &&
          !isPrimaryTouch(e)) return
          cancelLongTap()
  
          // swipe
          if ((touch.x2 && Math.abs(touch.x1 - touch.x2) > 30) ||
            (touch.y2 && Math.abs(touch.y1 - touch.y2) > 30)) {
            swipeTimeout = setTimeout(function () {
              if (touch.el) {
                touch.el.trigger('swipe')
                touch.el.trigger('swipe' + (swipeDirection(touch.x1, touch.x2, touch.y1, touch.y2)))
              }
              touch = {}
            }, 0)
          }
  
          // normal tap
          else if ('last' in touch)
          // don't fire tap when delta position changed by more than 30 pixels,
          // for instance when moving to a point and back to origin
          {
            if (deltaX < 30 && deltaY < 30) {
            // delay by one tick so we can cancel the 'tap' event if 'scroll' fires
            // ('tap' fires before 'scroll')
              tapTimeout = setTimeout(function () {
              // trigger universal 'tap' with the option to cancelTouch()
              // (cancelTouch cancels processing of single vs double taps for faster 'tap' response)
                var event = $.Event('tap')
                event.cancelTouch = cancelAll
                // [by paper] fix -> "TypeError: 'undefined' is not an object (evaluating 'touch.el.trigger'), when double tap
                if (touch.el) touch.el.trigger(event)
  
                // trigger double tap immediately
                if (touch.isDoubleTap) {
                  if (touch.el) touch.el.trigger('doubleTap')
                  touch = {}
                }
  
                // trigger single tap after 250ms of inactivity
                else {
                  touchTimeout = setTimeout(function () {
                    touchTimeout = null
                    if (touch.el) touch.el.trigger('singleTap')
                    touch = {}
                  }, 250)
                }
              }, 0)
            } else {
              touch = {}
            }
          }
          deltaX = deltaY = 0
        }
  
        $(document).on(eventMap.up, up)
          .on(eventMap.down, down)
          .on(eventMap.move, move)
  
        // when the browser window loses focus,
        // for example when a modal dialog is shown,
        // cancel all ongoing events
        $(document).on(eventMap.cancel, cancelAll)
  
        // scrolling the window indicates intention of the user
        // to scroll, not tap or swipe, so cancel all ongoing events
        $(window).on('scroll', cancelAll)
  
        initialized = true
      }
  
      ;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown',
        'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function (eventName) {
        $.fn[eventName] = function (callback) { return this.on(eventName, callback) }
      })
  
      $.touch = { setup: setup }
  
      $(document).ready(setup)
    })(Zepto)
  
    ;(function ($) {
      if ($.os.ios) {
        var gesture = {}; var gestureTimeout
  
        function parentIfText (node) {
          return 'tagName' in node ? node : node.parentNode
        }
  
        $(document).bind('gesturestart', function (e) {
          var now = Date.now(); var delta = now - (gesture.last || now)
          gesture.target = parentIfText(e.target)
          gestureTimeout && clearTimeout(gestureTimeout)
          gesture.e1 = e.scale
          gesture.last = now
        }).bind('gesturechange', function (e) {
          gesture.e2 = e.scale
        }).bind('gestureend', function (e) {
          if (gesture.e2 > 0) {
            Math.abs(gesture.e1 - gesture.e2) != 0 && $(gesture.target).trigger('pinch') &&
            $(gesture.target).trigger('pinch' + (gesture.e1 - gesture.e2 > 0 ? 'In' : 'Out'))
            gesture.e1 = gesture.e2 = gesture.last = 0
          } else if ('last' in gesture) {
            gesture = {}
          }
        })
  
        ;['pinch', 'pinchIn', 'pinchOut'].forEach(function (m) {
          $.fn[m] = function (callback) { return this.bind(m, callback) }
        })
      }
    })(Zepto)
  
    ;(function ($) {
      $.fn.end = function () {
        return this.prevObject || $()
      }
  
      $.fn.andSelf = function () {
        return this.add(this.prevObject || $())
      }
  
      'filter,add,not,eq,first,last,find,closest,parents,parent,children,siblings'.split(',').forEach(function (property) {
        var fn = $.fn[property]
        $.fn[property] = function () {
          var ret = fn.apply(this, arguments)
          ret.prevObject = this
          return ret
        }
      })
    })(Zepto)
  
    ;(function (undefined) {
      if (String.prototype.trim === undefined) // fix for iOS 3.2
      { String.prototype.trim = function () { return this.replace(/^\s+|\s+$/g, '') } }
  
      // For iOS 3.x
      // from https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reduce
      if (Array.prototype.reduce === undefined) {
        Array.prototype.reduce = function (fun) {
          if (this === void 0 || this === null) throw new TypeError()
          var t = Object(this); var len = t.length >>> 0; var k = 0; var accumulator
          if (typeof fun !== 'function') throw new TypeError()
          if (len == 0 && arguments.length == 1) throw new TypeError()
  
          if (arguments.length >= 2) { accumulator = arguments[1] } else {
            do {
              if (k in t) {
                accumulator = t[k++]
                break
              }
              if (++k >= len) throw new TypeError()
            } while (true)
          }
  
          while (k < len) {
            if (k in t) accumulator = fun.call(undefined, accumulator, t[k], k, t)
            k++
          }
          return accumulator
        }
      }
    })()
    return Zepto
  }))
  