zoukankan      html  css  js  c++  java
  • 移动端的silder,未封装,基于zepto的touch模块,有参照修改过touch的bug

    <!--html模块-->

    <header class="appoin-head">
    <ul>
    <li class="aa">
    <a href="#">
    <img src="img/banner1.png" alt=""> 
    </a>
    </li>
    <li>
    <a href="#">
    <img src="img/banner2.png" alt=""> 
    </a>
    </li>
    <li>
    <a href="#">
    <img src="img/banner3.png" alt=""> 
    </a>
    </li>
    <li>
    <a href="#">
    <img src="img/banner4.png" alt=""> 
    </a>
    </li>
    </ul>
    <ol></ol>
    </header>

    <!--css样式-->

    .appoin-head ol,.appoin-head ul {
    list-style: none;
    margin: 0;
    padding: 0;
    }
    
    .appoin-head ul li {
    float: left;
    }
    
    .clear:after {
    content: '';
    clear: both;
    display: block;
    }
    
    .clear {
    zoom: 1;
    }
    
    .mob3d, .appoin-head, .appoin-head ul, .appoin-head ul li {
    transform: translate3d(0, 0, 0);
    -webkit-transform: translate3d(0, 0, 0);
    -o-transform: translate3d(0, 0, 0);
    -moz-transform: translate3d(0, 0, 0);
    }
    
    .appoin-head {
    position: relative;
    width: 100%;
    overflow: hidden;
    }
    
    .appoin-head ul {
    width: 900%;
    height: 100%;
    -webkit-transition: all 0.5s 0s ease-in-out;
    }
    
    .appoin-head ul li a {
    display: block;
    width: 100%;
    }
    
    .appoin-head ul li a img {
    max-width: 100%;
    max-height: 100%;
    }
    
    .appoin-head ol {
    position: absolute;
    left: 50%;
    bottom: 0.7rem;
    }
    
    .appoin-head ol li {
    width: 0.7rem;
    height: 0.7rem;
    background: #ffffff;
    display: inline-block;
    margin: 0 0.2rem;
    -webkit-border-radius: 100%;
    -moz-border-radius: 100%;
    -mz-border-radius: 100%;
    -o-border-radius: 100%;
    border-radius: 100%;
    }
    
    .appoin-head ol li.active {
    background: #f897ae;
    }

    <!--js部分-->

    $(function() {
    var length = $('.appoin-head ul li').length,
    now = 0;
    var $li = $('.appoin-head ul li');
    $li.width($(window).width());
    var wid = $li.width();
    $('.appoin-head ul').width(wid * length);
    for (var i = 0; i < length; i++) {
    var html = '<li></li>';
    $('.appoin-head ol').append(html);
    }
    var olwidth = ($('.appoin-head ol').width()) / 2;
    $('.appoin-head ol').css('marginLeft', -olwidth);
    $('.appoin-head ol li').eq(now).addClass('active').siblings('li').removeClass('active');
    
    function silder() {
    $('.appoin-head ul').css("-webkit-transform", "translate3d(" + -wid * (now) + "px,0,0)");
    $('.appoin-head ol li').eq(now).addClass('active').siblings('li').removeClass('active');
    }
    $('.appoin-head ul li').swipeLeft(function(e) {
    now++;
    if (now > length - 1) now = 0;
    silder();
    })
    $('.appoin-head ul li').swipeRight(function(e) {
    now--;
    if (now < 0) now = length - 1;
    silder();
    })
    var time = setInterval(function() {
    now++;
    if (now > length - 1) now = 0;
    silder();
    }, 3000);
    $('.appoin-head ul li').on('touchstart', function() {
    clearInterval(time);
    })
    $('.appoin-head ul li').on('touchend', function() {
    time = setInterval(function() {
    now++;
    if (now > length - 1) now = 0;
    silder();
    }, 3000);
    })
    }());

    // 上面是banner图切换,touch的js部分有改动,修复安卓qq浏览器中的失效

    下面是zepto改后的源码,

    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    var Zepto = (function() {
      var undefined, key, $, classList, emptyArray = [], concat = emptyArray.concat, filter = emptyArray.filter, slice = emptyArray.slice,
        document = window.document,
        elementDisplay = {}, classCache = {},
        cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 },
        fragmentRE = /^s*<(w+|!)[^>]*>/,
        singleTagRE = /^<(w+)s*/?>(?:</1>|)$/,
        tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([w:]+)[^>]*)/>/ig,
        rootNodeRE = /^(?:body|html)$/i,
        capitalRE = /([A-Z])/g,
    
        // special attributes that should be get/set via method calls
        methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'],
    
        adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ],
        table = document.createElement('table'),
        tableRow = document.createElement('tr'),
        containers = {
          'tr': document.createElement('tbody'),
          'tbody': table, 'thead': table, 'tfoot': table,
          'td': tableRow, 'th': tableRow,
          '*': document.createElement('div')
        },
        readyRE = /complete|loaded|interactive/,
        simpleSelectorRE = /^[w-]*$/,
        class2type = {},
        toString = class2type.toString,
        zepto = {},
        camelize, uniq,
        tempParent = document.createElement('div'),
        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'
        },
        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.webkitMatchesSelector || element.mozMatchesSelector ||
                              element.oMatchesSelector || element.matchesSelector
        if (matchesSelector) return matchesSelector.call(element, selector)
        // fall back to performing a selector:
        var match, parent = element.parentNode, 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) { return typeof obj.length == 'number' }
    
      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-zd])([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, 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, 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,
            maybeID = selector[0] == '#',
            maybeClass = !maybeID && selector[0] == '.',
            nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked
            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 || '',
            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
      }
    
      $.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, values = [], i, 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, value, 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){
          // need to check if document.body exists for IE as that browser reports
          // document ready when it hasn't yet created the body element
          if (readyRE.test(document.readyState) && document.body) callback($)
          else document.addEventListener('DOMContentLoaded', function(){ callback($) }, 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 this.length > 0 && zepto.matches(this[0], 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, $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 node = this[0], collection = false
          if (typeof selector == 'object') collection = $(selector)
          while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector)))
            node = node !== context && !isDocument(node) && node.parentNode
          return $(node)
        },
        parents: function(selector){
          var ancestors = [], 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),
                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), contents = self.contents(),
                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)) ?
            (!this.length || this[0].nodeType !== 1 ? undefined :
              (!(result = this[0].getAttribute(name)) && name in this[0]) ? this[0][name] : result
            ) :
            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 (1 in arguments) ?
            this.each(function(idx){
              this[name] = funcArg(this, value, idx, this[name])
            }) :
            (this[0] && this[0][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){
          return 0 in arguments ?
            this.each(function(idx){
              this.value = funcArg(this, value, idx, this.value)
            }) :
            (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),
                coords = funcArg(this, coordinates, index, $this.offset()),
                parentOffset = $this.offsetParent().offset(),
                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 (!$.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,
             Math.round(obj.width),
            height: Math.round(obj.height)
          }
        },
        css: function(property, value){
          if (arguments.length < 2) {
            var computedStyle, element = this[0]
            if(!element) return
            computedStyle = getComputedStyle(element, '')
            if (typeof property == 'string')
              return element.style[camelize(property)] || computedStyle.getPropertyValue(property)
            else if (isArray(property)) {
              var props = {}
              $.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), 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), 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
            offsetParent = this.offsetParent(),
            // Get correct offsets
            offset       = this.offset(),
            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, 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, nodes = $.map(arguments, function(arg) {
                argType = type(arg)
                return argType == "object" || argType == "array" || arg == null ?
                  arg : zepto.fragment(arg)
              }),
              parent, 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)
                  window['eval'].call(window, 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 $
    })()
    
    // If `$` is not yet defined, point it to `Zepto`
    window.Zepto = Zepto
    window.$ === undefined && (window.$ = Zepto)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(function($){
      var jsonpID = 0,
          document = window.document,
          key,
          name,
          rscript = /<script[^<]*(?:(?!</script>)<[^<]*)*</script>/gi,
          scriptTypeRE = /^(?:text|application)/javascript/i,
          xmlTypeRE = /^(?:text|application)/xml/i,
          jsonType = 'application/json',
          htmlType = 'text/html',
          blankRE = /^s*$/,
          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, 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)
      }
    
      // Empty function, used as default callback
      function empty() {}
    
      $.ajaxJSONP = function(options, deferred){
        if (!('type' in options)) return $.ajax(options)
    
        var _callbackName = options.jsonpCallback,
          callbackName = ($.isFunction(_callbackName) ?
            _callbackName() : _callbackName) || ('jsonp' + (++jsonpID)),
          script = document.createElement('script'),
          originalCallback = window[callbackName],
          responseData,
          abort = function(errorType) {
            $(script).triggerHandler('error', errorType || 'abort')
          },
          xhr = { abort: abort }, 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
      }
    
      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.url = appendQuery(options.url, options.data), options.data = undefined
      }
    
      $.ajax = function(options){
        var settings = $.extend({}, options || {}),
            deferred = $.Deferred && $.Deferred(),
            urlAnchor, 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, hasPlaceholder = /?.+=?/.test(settings.url)
        if (hasPlaceholder) dataType = 'jsonp'
    
        if (settings.cache === false || (
             (!options || options.cache !== true) &&
             ('script' == dataType || 'jsonp' == dataType)
            ))
          settings.url = appendQuery(settings.url, '_=' + Date.now())
    
        if ('jsonp' == dataType) {
          if (!hasPlaceholder)
            settings.url = appendQuery(settings.url,
              settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?')
          return $.ajaxJSONP(settings, deferred)
        }
    
        var mime = settings.accepts[dataType],
            headers = { },
            setHeader = function(name, value) { headers[name.toLowerCase()] = [name, value] },
            protocol = /^([w-]+:)///.test(settings.url) ? RegExp.$1 : window.location.protocol,
            xhr = settings.xhr(),
            nativeSetHeader = xhr.setRequestHeader,
            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, 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/
                  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
        }
    
        if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name]
    
        var async = 'async' in settings ? settings.async : true
        xhr.open(settings.type, settings.url, async, settings.username, settings.password)
    
        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, parts = url.split(/s/), selector,
            options = parseArguments(url, data, success),
            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, array = $.isArray(obj), 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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(function($){
      var cache = [], 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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(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)
            fired,  // Flag to know if list was already fired
            firing, // Flag to know if list is currently firing
            firingStart, // First callback to fire (used internally by add and fireWith)
            firingLength, // End of the loop when firing
            firingIndex, // Index of currently firing callback (modified by remove if needed)
            list = [], // Actual callback list
            stack = !options.once && [], // Stack of fire calls for repeatable lists
            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()
              }
            },
    
            Callbacks = {
              add: function() {
                if (list) {
                  var start = list.length,
                      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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    // The following code is heavily inspired by jQuery's $.fn.data()
    
    ;(function($){
      var data = {}, dataAttr = $.fn.data, camelize = $.camelCase,
        exp = $.expando = 'Zepto' + (+new Date()), 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], 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),
          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) })
      }
    
      $.fn.removeData = function(names) {
        if (typeof names == 'string') names = names.split(/s+/)
        return this.each(function(){
          var id = this[exp], 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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    //
    //     Some code (c) 2005, 2013 jQuery Foundation, Inc. and other contributors
    
    ;(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}) ]
            ],
            state = "pending",
            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,
                            values = fn ? [returned] : arguments
                        defer[tuple[0] + "With"](context, values)
                      }
                    })
                  })
                  fns = null
                }).promise()
              },
    
              promise: function(obj) {
                return obj != null ? $.extend( obj, promise ) : promise
              }
            },
            deferred = {}
    
        $.each(tuples, function(i, tuple){
          var list = tuple[2],
              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),
            len = resolveValues.length,
            i = 0,
            remain = len !== 1 || (sub && $.isFunction(sub.promise)) ? len : 0,
            deferred = remain === 1 ? sub : Deferred(),
            progressValues, progressContexts, resolveContexts,
            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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(function($){
      function detect(ua, platform){
        var os = this.os = {}, browser = this.browser = {},
          webkit = ua.match(/Web[kK]it[/]{0,1}([d.]+)/),
          android = ua.match(/(Android);?[s/]+([d.]+)?/),
          osx = !!ua.match(/(Macintosh; Intel /),
          ipad = ua.match(/(iPad).*OSs([d_]+)/),
          ipod = ua.match(/(iPod)(.*OSs([d_]+))?/),
          iphone = !ipad && ua.match(/(iPhonesOS)s([d_]+)/),
          webos = ua.match(/(webOS|hpwOS)[s/]([d.]+)/),
          win = /Wind{2}|Windows/.test(platform),
          wp = ua.match(/Windows Phone ([d.]+)/),
          touchpad = webos && ua.match(/TouchPad/),
          kindle = ua.match(/Kindle/([d.]+)/),
          silk = ua.match(/Silk/([d._]+)/),
          blackberry = ua.match(/(BlackBerry).*Version/([d.]+)/),
          bb10 = ua.match(/(BB10).*Version/([d.]+)/),
          rimtabletos = ua.match(/(RIMsTabletsOS)s([d.]+)/),
          playbook = ua.match(/PlayBook/),
          chrome = ua.match(/Chrome/([d.]+)/) || ua.match(/CriOS/([d.]+)/),
          firefox = ua.match(/Firefox/([d.]+)/),
          firefoxos = ua.match(/((?:Mobile|Tablet); rv:([d.]+)).*Firefox/[d.]+/),
          ie = ua.match(/MSIEs([d.]+)/) || ua.match(/Trident/[d](?=[^?]+).*rv:([0-9.].)/),
          webview = !chrome && ua.match(/(iPhone|iPod|iPad).*AppleWebKit(?!.*Safari)/),
          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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(function($){
      var _zid = 1, undefined,
          slice = Array.prototype.slice,
          isFunction = $.isFunction,
          isString = function(obj){ return typeof obj == 'string' },
          handlers = {},
          specialEvents={},
          focusinSupported = 'onfocusin' in window,
          focus = { focus: 'focusin', blur: 'focusout' },
          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), 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},
          returnFalse = function(){return false},
          ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$)/,
          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
          })
    
          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, 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, delegator, $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, 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'), 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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(function($){
      $.fn.serializeArray = function() {
        var name, type, result = [],
          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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(function($, undefined){
      var prefix = '', eventPrefix,
        vendors = { Webkit: 'webkit', Moz: '', O: 'o' },
        testEl = document.createElement('div'),
        supportedTransforms = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i,
        transform,
        transitionProperty, transitionDuration, transitionTiming, transitionDelay,
        animationName, animationDuration, animationTiming, animationDelay,
        cssReset = {}
    
      function dasherize(str) { return str.replace(/([a-z])([A-Z])/, '$1-$2').toLowerCase() }
      function normalizeEvent(name) { return eventPrefix ? eventPrefix + name : name.toLowerCase() }
    
      $.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, cssValues = {}, cssProperties, transforms = '',
            that = this, wrappedCallback, endEvent = $.fx.transitionEnd,
            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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(function($, undefined){
      var document = window.document, docElem = document.documentElement,
        origShow = $.fn.show, origHide = $.fn.hide, 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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(function($){
      if ($.os.ios) {
        var gesture = {}, gestureTimeout
    
        function parentIfText(node){
          return 'tagName' in node ? node : node.parentNode
        }
    
        $(document).bind('gesturestart', function(e){
          var now = Date.now(), 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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(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){
          try {
            return nativeGetComputedStyle(element)
          } catch(e) {
            return null
          }
        }
      }
    })()
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(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), len = t.length >>> 0, k = 0, 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
        }
    
    })()
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(function($){
      var zepto = $.zepto, oldQsa = zepto.qsa, 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*'),
          childRe  = /^s*>/,
          classTag = 'Zepto' + (+new Date())
    
      function process(sel, fn) {
        // quote the hash in `a[href^=#]` expression
        sel = sel.replace(/=#]/g, '="#"]')
        var filter, arg, 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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(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)
    
    //     Zepto.js
    //     (c) 2010-2016 Thomas Fuchs
    //     Zepto.js may be freely distributed under the MIT license.
    
    ;(function($){
      var touch = {},
        touchTimeout, tapTimeout, swipeTimeout, longTapTimeout,
        longTapDelay = 750,
        gesture
    
      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)
      }
    
      $(document).ready(function(){
        var now, delta, deltaX = 0, deltaY = 0, firstTouch, _isPointerType
    
        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)
            }
          })
          .on('touchstart MSPointerDown pointerdown', 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);
          })
          .on('touchmove MSPointerMove pointermove', 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)
             if (touch.x2 && Math.abs(touch.x1 - touch.x2) > 10)
                e.preventDefault();
          })
          .on('touchend MSPointerUp pointerup', 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() {
                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
                  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
    
          })
          // when the browser window loses focus,
          // for example when a modal dialog is shown,
          // cancel all ongoing events
          .on('touchcancel MSPointerCancel pointercancel', cancelAll)
    
        // scrolling the window indicates intention of the user
        // to scroll, not tap or swipe, so cancel all ongoing events
        $(window).on('scroll', cancelAll)
      })
    
      ;['swipe', 'swipeLeft', 'swipeRight', 'swipeUp', 'swipeDown',
        'doubleTap', 'tap', 'singleTap', 'longTap'].forEach(function(eventName){
        $.fn[eventName] = function(callback){ return this.on(eventName, callback) }
      })
    })(Zepto)
  • 相关阅读:
    SCI写作经典替换词,瞬间高大上!(转)
    最佳化常用测试函数 Optimization Test functions
    算法复杂度速查表
    VS 代码行统计
    CPLEX IDE 菜单栏语言设置( 中文 英文 韩文 等多国语言 设置)
    如何从PDF文件中提取矢量图
    Matlab无法打开M文件的错误( Undefined function or method 'uiopen' for input arguments of type 'char)
    visual studio 资源视图 空白 解决方案
    MFC DialogBar 按钮灰色不响应
    嗨翻C语言笔记(二)
  • 原文地址:https://www.cnblogs.com/jldiary/p/5571830.html
Copyright © 2011-2022 走看看