淘宝评论数据抓取简记

        刚才趴在床上搞清楚了淘宝评论数据的抓取方法,在此记录,以备后用。

        淘宝商品详情页面下方有如下script: 


<script>
    window.App = (window.App || {});
    window.App.data = {
        images: [
                                        "http://q.i02.wimg.taobao.com/bao/uploaded/i3/T1O2eYXjdsXXXQBm.Y_030602.jpg"
                ,                            "http://q.i01.wimg.taobao.com/bao/uploaded/i1/T1QMCxXi0fXXcyDbPb_093241.jpg"
                ,                            "http://q.i02.wimg.taobao.com/bao/uploaded/i2/670343779/T29dyXXchbXXXXXXXX_!!670343779.png"
                ,                            "http://q.i02.wimg.taobao.com/bao/uploaded/i3/670343779/T2419rXdXbXXXXXXXX_!!670343779.png"
                ,                            "http://q.i03.wimg.taobao.com/bao/uploaded/i2/T1eYO0XXhkXXaJ60na_120515.jpg"
                                    ],

        link:  "http://a.m.tmall.com/i9642784141.htm",
        price: "¥202.00",

        tmall: true,
        itemId: 9642784141,
        hasProps: false,

                taoPlus: true,

                        imgScale: 1,

        reAddCart:  false ,
        reAddFav:  false ,
        prevSkuId: "",

        logAjaxUrl: "ajax/pds.do",
        descAjaxUrl:   "http://a.m.tmall.com/ajax/desc_list.do?item_id=xxx&ps=800&sid=6c4d94e0e89bca18",
        propsAjaxUrl:  "http://a.m.tmall.com/ajax/sku.do?item_id=xxx&sid=6c4d94e0e89bca18",
        reviewAjaxUrl: "http://a.m.tmall.com/ajax/rate_list.do?item_id=xxx&sid=6c4d94e0e89bca18",
        loginUrl: "http://login.m.taobao.com/login.htm?tpl_redirect_url=http%3A%2F%2Fa.m.tmall.com%2Fi9642784141.htm%3Fsid%3D6c4d94e0e89bca18%26pds%3Dfromauc%2523h%2523shop&sid=6c4d94e0e89bca18",

        addFavUrl:  "http://fav.m.taobao.com/favorite/to_collection.htm?itemNumId=xxx&xid=0db2&pds=addfav%23h%23detail&sid=6c4d94e0e89bca18",
        addCartUrl: "http://cart.m.taobao.com/ajax.do?fun=add&item_id=xxx&ticket=6c4d94e0e89bca18&pds=addcart%23h%23detail&sid=6c4d94e0e89bca18",
        cleannowUrl: "http://cart.m.taobao.com/my_cart.htm?pds=cleannow%23h%23cart&sid=6c4d94e0e89bca18",
        myCartUrl: "http://cart.m.taobao.com/my_cart.htm?sid=6c4d94e0e89bca18",
        recommendAjaxUrl: "http://a.m.tmall.com/ajax/get_related.do?item_id=xxx&sid=6c4d94e0e89bca18"
    }
</script><script src="http://a.tbcdn.cn/mw/app/detail/h5/detail.min.js"></script>

reviewAjaxUrl: "http://a.m.tmall.com/ajax/rate_list.do?item_id=xxx
这个即为获取评论数据的Ajax链接,item_id为商品的编号。但是,直接输入上述网址只能获取少量评论数据。于是,问题就转到了如何获取链接后的其他参数。

打开http://a.tbcdn.cn/mw/app/detail/h5/detail.min.js,里面乱糟糟一片,啥也看不明白。找个js整理工具吧。

通过Google搜索,找到这个在线工具:http://jsbeautifier.org

经过格式整理后,脚本内容如下:


/* Zepto v1.0rc1 - polyfill zepto event detect fx ajax form touch - zeptojs.com/license */
(function (a) {
    String.prototype.trim === a && (String.prototype.trim = function () {
        return this.replace(/^\s+/, "").replace(/\s+$/, "")
    }), Array.prototype.reduce === a && (Array.prototype.reduce = function (b) {
        if (this === void 0 || this === null) throw new TypeError;
        var c = Object(this),
            d = c.length >>> 0,
            e = 0,
            f;
        if (typeof b != "function") throw new TypeError;
        if (d == 0 && arguments.length == 1) throw new TypeError;
        if (arguments.length >= 2) f = arguments[1];
        else do {
            if (e in c) {
                f = c[e++];
                break
            }
            if (++e >= d) throw new TypeError
        } while (!0);
        while (e < d) e in c && (f = b.call(a, f, c[e], e, c)), e++;
        return f
    })
})();
var Zepto = function () {
    function A(a) {
        return v.call(a) == "[object Function]"
    }
    function B(a) {
        return a instanceof Object
    }
    function C(b) {
        var c, d;
        if (v.call(b) !== "[object Object]") return !1;
        d = A(b.constructor) && b.constructor.prototype;
        if (!d || !hasOwnProperty.call(d, "isPrototypeOf")) return !1;
        for (c in b);
        return c === a || hasOwnProperty.call(b, c)
    }
    function D(a) {
        return a instanceof Array
    }
    function E(a) {
        return typeof a.length == "number"
    }
    function F(b) {
        return b.filter(function (b) {
            return b !== a && b !== null
        })
    }
    function G(a) {
        return a.length > 0 ? [].concat.apply([], a) : a
    }
    function H(a) {
        return a.replace(/::/g, "/").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").replace(/_/g, "-").toLowerCase()
    }
    function I(a) {
        return a in i ? i[a] : i[a] = new RegExp("(^|\\s)" + a + "(\\s|$)")
    }
    function J(a, b) {
        return typeof b == "number" && !k[H(a)] ? b + "px" : b
    }
    function K(a) {
        var b, c;
        return h[a] || (b = g.createElement(a), g.body.appendChild(b), c = j(b, "").getPropertyValue("display"), b.parentNode.removeChild(b), c == "none" && (c = "block"), h[a] = c), h[a]
    }
    function L(b, d) {
        return d === a ? c(b) : c(b).filter(d)
    }
    function M(a, b, c, d) {
        return A(b) ? b.call(a, c, d) : b
    }
    function N(a, b, d) {
        var e = a % 2 ? b : b.parentNode;
        e ? e.insertBefore(d, a ? a == 1 ? e.firstChild : a == 2 ? b : null : b.nextSibling) : c(d).remove()
    }
    function O(a, b) {
        b(a);
        for (var c in a.childNodes) O(a.childNodes[c], b)
    }
    var a, b, c, d, e = [],
        f = e.slice,
        g = window.document,
        h = {}, i = {}, j = g.defaultView.getComputedStyle,
        k = {
            "column-count": 1,
            columns: 1,
            "font-weight": 1,
            "line-height": 1,
            opacity: 1,
            "z-index": 1,
            zoom: 1
        }, l = /^\s*<(\w+|!)[^>]*>/,
        m = [1, 3, 8, 9, 11],
        n = ["after", "prepend", "before", "append"],
        o = g.createElement("table"),
        p = g.createElement("tr"),
        q = {
            tr: g.createElement("tbody"),
            tbody: o,
            thead: o,
            tfoot: o,
            td: p,
            th: p,
            "*": g.createElement("div")
        }, r = /complete|loaded|interactive/,
        s = /^\.([\w-]+)$/,
        t = /^#([\w-]+)$/,
        u = /^[\w-]+$/,
        v = {}.toString,
        w = {}, x, y, z = g.createElement("div");
    return w.matches = function (a, b) {
        if (!a || a.nodeType !== 1) return !1;
        var c = a.webkitMatchesSelector || a.mozMatchesSelector || a.oMatchesSelector || a.matchesSelector;
        if (c) return c.call(a, b);
        var d, e = a.parentNode,
            f = !e;
        return f && (e = z).appendChild(a), d = ~w.qsa(e, b).indexOf(a), f && z.removeChild(a), d
    }, x = function (a) {
        return a.replace(/-+(.)?/g, function (a, b) {
            return b ? b.toUpperCase() : ""
        })
    }, y = function (a) {
        return a.filter(function (b, c) {
            return a.indexOf(b) == c
        })
    }, w.fragment = function (b, d) {
        d === a && (d = l.test(b) && RegExp.$1), d in q || (d = "*");
        var e = q[d];
        return e.innerHTML = "" + b, c.each(f.call(e.childNodes), function () {
            e.removeChild(this)
        })
    }, w.Z = function (a, b) {
        return a = a || [], a.__proto__ = arguments.callee.prototype, a.selector = b || "", a
    }, w.isZ = function (a) {
        return a instanceof w.Z
    }, w.init = function (b, d) {
        if (!b) return w.Z();
        if (A(b)) return c(g).ready(b);
        if (w.isZ(b)) return b;
        var e;
        if (D(b)) e = F(b);
        else if (C(b)) e = [c.extend({}, b)], b = null;
        else if (m.indexOf(b.nodeType) >= 0 || b === window) e = [b], b = null;
        else if (l.test(b)) e = w.fragment(b.trim(), RegExp.$1), b = null;
        else {
            if (d !== a) return c(d).find(b);
            e = w.qsa(g, b)
        }
        return w.Z(e, b)
    }, c = function (a, b) {
        return w.init(a, b)
    }, c.extend = function (c) {
        return f.call(arguments, 1).forEach(function (d) {
            for (b in d) d[b] !== a && (c[b] = d[b])
        }), c
    }, w.qsa = function (a, b) {
        var c;
        return a === g && t.test(b) ? (c = a.getElementById(RegExp.$1)) ? [c] : e : a.nodeType !== 1 && a.nodeType !== 9 ? e : f.call(s.test(b) ? a.getElementsByClassName(RegExp.$1) : u.test(b) ? a.getElementsByTagName(b) : a.querySelectorAll(b))
    }, c.isFunction = A, c.isObject = B, c.isArray = D, c.isPlainObject = C, c.inArray = function (a, b, c) {
        return e.indexOf.call(b, a, c)
    }, c.trim = function (a) {
        return a.trim()
    }, c.uuid = 0, c.map = function (a, b) {
        var c, d = [],
            e, f;
        if (E(a)) for (e = 0; e < a.length; e++) c = b(a[e], e), c != null && d.push(c);
        else for (f in a) c = b(a[f], f), c != null && d.push(c);
        return G(d)
    }, c.each = function (a, b) {
        var c, d;
        if (E(a)) {
            for (c = 0; c < a.length; c++) if (b.call(a[c], c, a[c]) === !1) return a
        } else for (d in a) if (b.call(a[d], d, a[d]) === !1) return a;
        return a
    }, c.fn = {
        forEach: e.forEach,
        reduce: e.reduce,
        push: e.push,
        indexOf: e.indexOf,
        concat: e.concat,
        map: function (a) {
            return c.map(this, function (b, c) {
                return a.call(b, c, b)
            })
        },
        slice: function () {
            return c(f.apply(this, arguments))
        },
        ready: function (a) {
            return r.test(g.readyState) ? a(c) : g.addEventListener("DOMContentLoaded", function () {
                a(c)
            }, !1), this
        },
        get: function (b) {
            return b === a ? f.call(this) : this[b]
        },
        toArray: function () {
            return this.get()
        },
        size: function () {
            return this.length
        },
        remove: function () {
            return this.each(function () {
                this.parentNode != null && this.parentNode.removeChild(this)
            })
        },
        each: function (a) {
            return this.forEach(function (b, c) {
                a.call(b, c, b)
            }), this
        },
        filter: function (a) {
            return c([].filter.call(this, function (b) {
                return w.matches(b, a)
            }))
        },
        add: function (a, b) {
            return c(y(this.concat(c(a, b))))
        },
        is: function (a) {
            return this.length > 0 && w.matches(this[0], a)
        },
        not: function (b) {
            var d = [];
            if (A(b) && b.call !== a) this.each(function (a) {
                b.call(this, a) || d.push(this)
            });
            else {
                var e = typeof b == "string" ? this.filter(b) : E(b) && A(b.item) ? f.call(b) : c(b);
                this.forEach(function (a) {
                    e.indexOf(a) < 0 && d.push(a)
                })
            }
            return c(d)
        },
        eq: function (a) {
            return a === -1 ? this.slice(a) : this.slice(a, + a + 1)
        },
        first: function () {
            var a = this[0];
            return a && !B(a) ? a : c(a)
        },
        last: function () {
            var a = this[this.length - 1];
            return a && !B(a) ? a : c(a)
        },
        find: function (a) {
            var b;
            return this.length == 1 ? b = w.qsa(this[0], a) : b = this.map(function () {
                return w.qsa(this, a)
            }), c(b)
        },
        closest: function (a, b) {
            var d = this[0];
            while (d && !w.matches(d, a)) d = d !== b && d !== g && d.parentNode;
            return c(d)
        },
        parents: function (a) {
            var b = [],
                d = this;
            while (d.length > 0) d = c.map(d, function (a) {
                if ((a = a.parentNode) && a !== g && b.indexOf(a) < 0) return b.push(a), a
            });
            return L(b, a)
        },
        parent: function (a) {
            return L(y(this.pluck("parentNode")), a)
        },
        children: function (a) {
            return L(this.map(function () {
                return f.call(this.children)
            }), a)
        },
        siblings: function (a) {
            return L(this.map(function (a, b) {
                return f.call(b.parentNode.children).filter(function (a) {
                    return a !== b
                })
            }), a)
        },
        empty: function () {
            return this.each(function () {
                this.innerHTML = ""
            })
        },
        pluck: function (a) {
            return this.map(function () {
                return this[a]
            })
        },
        show: function () {
            return this.each(function () {
                this.style.display == "none" && (this.style.display = null), j(this, "").getPropertyValue("display") == "none" && (this.style.display = K(this.nodeName))
            })
        },
        replaceWith: function (a) {
            return this.before(a).remove()
        },
        wrap: function (a) {
            return this.each(function () {
                c(this).wrapAll(c(a)[0].cloneNode(!1))
            })
        },
        wrapAll: function (a) {
            return this[0] && (c(this[0]).before(a = c(a)), a.append(this)), this
        },
        unwrap: function () {
            return this.parent().each(function () {
                c(this).replaceWith(c(this).children())
            }), this
        },
        clone: function () {
            return c(this.map(function () {
                return this.cloneNode(!0)
            }))
        },
        hide: function () {
            return this.css("display", "none")
        },
        toggle: function (b) {
            return (b === a ? this.css("display") == "none" : b) ? this.show() : this.hide()
        },
        prev: function () {
            return c(this.pluck("previousElementSibling"))
        },
        next: function () {
            return c(this.pluck("nextElementSibling"))
        },
        html: function (b) {
            return b === a ? this.length > 0 ? this[0].innerHTML : null : this.each(function (a) {
                var d = this.innerHTML;
                c(this).empty().append(M(this, b, a, d))
            })
        },
        text: function (b) {
            return b === a ? this.length > 0 ? this[0].textContent : null : this.each(function () {
                this.textContent = b
            })
        },
        attr: function (c, d) {
            var e;
            return typeof c == "string" && d === a ? this.length == 0 || this[0].nodeType !== 1 ? a : c == "value" && this[0].nodeName == "INPUT" ? this.val() : !(e = this[0].getAttribute(c)) && c in this[0] ? this[0][c] : e : this.each(function (a) {
                if (this.nodeType !== 1) return;
                if (B(c)) for (b in c) this.setAttribute(b, c[b]);
                else this.setAttribute(c, M(this, d, a, this.getAttribute(c)))
            })
        },
        removeAttr: function (a) {
            return this.each(function () {
                this.nodeType === 1 && this.removeAttribute(a)
            })
        },
        prop: function (b, c) {
            return c === a ? this[0] ? this[0][b] : a : this.each(function (a) {
                this[b] = M(this, c, a, this[b])
            })
        },
        data: function (b, c) {
            var d = this.attr("data-" + H(b), c);
            return d !== null ? d : a
        },
        val: function (b) {
            return b === a ? this.length > 0 ? this[0].value : a : this.each(function (a) {
                this.value = M(this, b, a, this.value)
            })
        },
        offset: function () {
            if (this.length == 0) return null;
            var a = this[0].getBoundingClientRect();
            return {
                left: a.left + window.pageXOffset,
                top: a.top + window.pageYOffset,
                width: a.width,
                height: a.height
            }
        },
        css: function (c, d) {
            if (d === a && typeof c == "string") return this.length == 0 ? a : this[0].style[x(c)] || j(this[0], "").getPropertyValue(c);
            var e = "";
            for (b in c) typeof c[b] == "string" && c[b] == "" ? this.each(function () {
                this.style.removeProperty(H(b))
            }) : e += H(b) + ":" + J(b, c[b]) + ";";
            return typeof c == "string" && (d == "" ? this.each(function () {
                this.style.removeProperty(H(c))
            }) : e = H(c) + ":" + J(c, d)), this.each(function () {
                this.style.cssText += ";" + e
            })
        },
        index: function (a) {
            return a ? this.indexOf(c(a)[0]) : this.parent().children().indexOf(this[0])
        },
        hasClass: function (a) {
            return this.length < 1 ? !1 : I(a).test(this[0].className)
        },
        addClass: function (a) {
            return this.each(function (b) {
                d = [];
                var e = this.className,
                    f = M(this, a, b, e);
                f.split(/\s+/g).forEach(function (a) {
                    c(this).hasClass(a) || d.push(a)
                }, this), d.length && (this.className += (e ? " " : "") + d.join(" "))
            })
        },
        removeClass: function (b) {
            return this.each(function (c) {
                if (b === a) return this.className = "";
                d = this.className, M(this, b, c, d).split(/\s+/g).forEach(function (a) {
                    d = d.replace(I(a), " ")
                }), this.className = d.trim()
            })
        },
        toggleClass: function (b, d) {
            return this.each(function (e) {
                var f = M(this, b, e, this.className);
                (d === a ? !c(this).hasClass(f) : d) ? c(this).addClass(f) : c(this).removeClass(f)
            })
        }
    }, ["width", "height"].forEach(function (b) {
        c.fn[b] = function (d) {
            var e, f = b.replace(/./, function (a) {
                return a[0].toUpperCase()
            });
            return d === a ? this[0] == window ? window["inner" + f] : this[0] == g ? g.documentElement["offset" + f] : (e = this.offset()) && e[b] : this.each(function (a) {
                var e = c(this);
                e.css(b, M(this, d, a, e[b]()))
            })
        }
    }), n.forEach(function (a, b) {
        c.fn[a] = function () {
            var a = c.map(arguments, function (a) {
                return B(a) ? a : w.fragment(a)
            });
            if (a.length < 1) return this;
            var d = this.length,
                e = d > 1,
                f = b < 2;
            return this.each(function (c, g) {
                for (var h = 0; h < a.length; h++) {
                    var i = a[f ? a.length - h - 1 : h];
                    O(i, function (a) {
                        a.nodeName != null && a.nodeName.toUpperCase() === "SCRIPT" && (!a.type || a.type === "text/javascript") && window.eval.call(window, a.innerHTML)
                    }), e && c < d - 1 && (i = i.cloneNode(!0)), N(b, g, i)
                }
            })
        }, c.fn[b % 2 ? a + "To" : "insert" + (b ? "Before" : "After")] = function (b) {
            return c(b)[a](this), this
        }
    }), w.Z.prototype = c.fn, w.camelize = x, w.uniq = y, c.zepto = w, c
}();
window.Zepto = Zepto, "$" in window || (window.$ = Zepto),
function (a) {
    function f(a) {
        return a._zid || (a._zid = d++)
    }
    function g(a, b, d, e) {
        b = h(b);
        if (b.ns) var g = i(b.ns);
        return (c[f(a)] || []).filter(function (a) {
            return a && (!b.e || a.e == b.e) && (!b.ns || g.test(a.ns)) && (!d || f(a.fn) === f(d)) && (!e || a.sel == e)
        })
    }
    function h(a) {
        var b = ("" + a).split(".");
        return {
            e: b[0],
            ns: b.slice(1).sort().join(" ")
        }
    }
    function i(a) {
        return new RegExp("(?:^| )" + a.replace(" ", " .* ?") + "(?: |$)")
    }
    function j(b, c, d) {
        a.isObject(b) ? a.each(b, d) : b.split(/\s/).forEach(function (a) {
            d(a, c)
        })
    }
    function k(b, d, e, g, i, k) {
        k = !! k;
        var l = f(b),
            m = c[l] || (c[l] = []);
        j(d, e, function (c, d) {
            var e = i && i(d, c),
                f = e || d,
                j = function (a) {
                    var c = f.apply(b, [a].concat(a.data));
                    return c === !1 && a.preventDefault(), c
                }, l = a.extend(h(c), {
                    fn: d,
                    proxy: j,
                    sel: g,
                    del: e,
                    i: m.length
                });
            m.push(l), b.addEventListener(l.e, j, k)
        })
    }
    function l(a, b, d, e) {
        var h = f(a);
        j(b || "", d, function (b, d) {
            g(a, b, d, e).forEach(function (b) {
                delete c[h][b.i], a.removeEventListener(b.e, b.proxy, !1)
            })
        })
    }
    function p(b) {
        var c = a.extend({
            originalEvent: b
        }, b);
        return a.each(o, function (a, d) {
            c[a] = function () {
                return this[d] = m, b[a].apply(b, arguments)
            }, c[d] = n
        }), c
    }
    function q(a) {
        if (!("defaultPrevented" in a)) {
            a.defaultPrevented = !1;
            var b = a.preventDefault;
            a.preventDefault = function () {
                this.defaultPrevented = !0, b.call(this)
            }
        }
    }
    var b = a.zepto.qsa,
        c = {}, d = 1,
        e = {};
    e.click = e.mousedown = e.mouseup = e.mousemove = "MouseEvents", a.event = {
        add: k,
        remove: l
    }, a.proxy = function (b, c) {
        if (a.isFunction(b)) {
            var d = function () {
                return b.apply(c, arguments)
            };
            return d._zid = f(b), d
        }
        if (typeof c == "string") return a.proxy(b[c], b);
        throw new TypeError("expected function")
    }, a.fn.bind = function (a, b) {
        return this.each(function () {
            k(this, a, b)
        })
    }, a.fn.unbind = function (a, b) {
        return this.each(function () {
            l(this, a, b)
        })
    }, a.fn.one = function (a, b) {
        return this.each(function (c, d) {
            k(this, a, b, null, function (a, b) {
                return function () {
                    var c = a.apply(d, arguments);
                    return l(d, b, a), c
                }
            })
        })
    };
    var m = function () {
        return !0
    }, n = function () {
        return !1
    }, o = {
        preventDefault: "isDefaultPrevented",
        stopImmediatePropagation: "isImmediatePropagationStopped",
        stopPropagation: "isPropagationStopped"
    };
    a.fn.delegate = function (b, c, d) {
        var e = !1;
        if (c == "blur" || c == "focus") a.iswebkit ? c = c == "blur" ? "focusout" : c == "focus" ? "focusin" : c : e = !0;
        return this.each(function (f, g) {
            k(g, c, d, b, function (c) {
                return function (d) {
                    var e, f = a(d.target).closest(b, g).get(0);
                    if (f) return e = a.extend(p(d), {
                        currentTarget: f,
                        liveFired: g
                    }), c.apply(f, [e].concat([].slice.call(arguments, 1)))
                }
            }, e)
        })
    }, a.fn.undelegate = function (a, b, c) {
        return this.each(function () {
            l(this, b, c, a)
        })
    }, a.fn.live = function (b, c) {
        return a(document.body).delegate(this.selector, b, c), this
    }, a.fn.die = function (b, c) {
        return a(document.body).undelegate(this.selector, b, c), this
    }, a.fn.on = function (b, c, d) {
        return c == undefined || a.isFunction(c) ? this.bind(b, c) : this.delegate(c, b, d)
    }, a.fn.off = function (b, c, d) {
        return c == undefined || a.isFunction(c) ? this.unbind(b, c) : this.undelegate(c, b, d)
    }, a.fn.trigger = function (b, c) {
        return typeof b == "string" && (b = a.Event(b)), q(b), b.data = c, this.each(function () {
            "dispatchEvent" in this && this.dispatchEvent(b)
        })
    }, a.fn.triggerHandler = function (b, c) {
        var d, e;
        return this.each(function (f, h) {
            d = p(typeof b == "string" ? a.Event(b) : b), d.data = c, d.target = h, a.each(g(h, b.type || b), function (a, b) {
                e = b.proxy(d);
                if (d.isImmediatePropagationStopped()) return !1
            })
        }), e
    }, "focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout change select keydown keypress keyup error".split(" ").forEach(function (b) {
        a.fn[b] = function (a) {
            return this.bind(b, a)
        }
    }), ["focus", "blur"].forEach(function (b) {
        a.fn[b] = function (a) {
            if (a) this.bind(b, a);
            else if (this.length) try {
                this.get(0)[b]()
            } catch (c) {}
            return this
        }
    }), a.Event = function (a, b) {
        var c = document.createEvent(e[a] || "Events"),
            d = !0;
        if (b) for (var f in b) f == "bubbles" ? d = !! b[f] : c[f] = b[f];
        return c.initEvent(a, d, !0, null, null, null, null, null, null, null, null, null, null, null, null), c
    }
}(Zepto),
function (a) {
    function b(a) {
        var b = this.os = {}, c = this.browser = {}, d = a.match(/WebKit\/([\d.]+)/),
            e = a.match(/(Android)\s+([\d.]+)/),
            f = a.match(/(iPad).*OS\s([\d_]+)/),
            g = !f && a.match(/(iPhone\sOS)\s([\d_]+)/),
            h = a.match(/(webOS|hpwOS)[\s\/]([\d.]+)/),
            i = h && a.match(/TouchPad/),
            j = a.match(/Kindle\/([\d.]+)/),
            k = a.match(/Silk\/([\d._]+)/),
            l = a.match(/(BlackBerry).*Version\/([\d.]+)/);
        if (c.webkit = !! d) c.version = d[1];
        e && (b.android = !0, b.version = e[2]), g && (b.ios = b.iphone = !0, b.version = g[2].replace(/_/g, ".")), f && (b.ios = b.ipad = !0, b.version = f[2].replace(/_/g, ".")), h && (b.webos = !0, b.version = h[2]), i && (b.touchpad = !0), l && (b.blackberry = !0, b.version = l[2]), j && (b.kindle = !0, b.version = j[1]), k && (c.silk = !0, c.version = k[1]), !k && b.android && a.match(/Kindle Fire/) && (c.silk = !0)
    }
    b.call(a, navigator.userAgent), a.__detect = b
}(Zepto),
function (a, b) {
    function l(a) {
        return a.toLowerCase()
    }
    function m(a) {
        return d ? d + a : l(a)
    }
    var c = "",
        d, e, f, g = {
            Webkit: "webkit",
            Moz: "",
            O: "o",
            ms: "MS"
        }, h = window.document,
        i = h.createElement("div"),
        j = /^((translate|rotate|scale)(X|Y|Z|3d)?|matrix(3d)?|perspective|skew(X|Y)?)$/i,
        k = {};
    a.each(g, function (a, e) {
        if (i.style[a + "TransitionProperty"] !== b) return c = "-" + l(a) + "-", d = e, !1
    }), k[c + "transition-property"] = k[c + "transition-duration"] = k[c + "transition-timing-function"] = k[c + "animation-name"] = k[c + "animation-duration"] = "", a.fx = {
        off: d === b && i.style.transitionProperty === b,
        cssPrefix: c,
        transitionEnd: m("TransitionEnd"),
        animationEnd: m("AnimationEnd")
    }, a.fn.animate = function (b, c, d, e) {
        return a.isObject(c) && (d = c.easing, e = c.complete, c = c.duration), c && (c /= 1e3), this.anim(b, c, d, e)
    }, a.fn.anim = function (d, e, f, g) {
        var h, i = {}, l, m = this,
            n, o = a.fx.transitionEnd;
        e === b && (e = .4), a.fx.off && (e = 0);
        if (typeof d == "string") i[c + "animation-name"] = d, i[c + "animation-duration"] = e + "s", o = a.fx.animationEnd;
        else {
            for (l in d) j.test(l) ? (h || (h = []), h.push(l + "(" + d[l] + ")")) : i[l] = d[l];
            h && (i[c + "transform"] = h.join(" ")), !a.fx.off && typeof d == "object" && (i[c + "transition-property"] = Object.keys(d).join(", "), i[c + "transition-duration"] = e + "s", i[c + "transition-timing-function"] = f || "linear")
        }
        return n = function (b) {
            if (typeof b != "undefined") {
                if (b.target !== b.currentTarget) return;
                a(b.target).unbind(o, arguments.callee)
            }
            a(this).css(k), g && g.call(this)
        }, e > 0 && this.bind(o, n), setTimeout(function () {
            m.css(i), e <= 0 && setTimeout(function () {
                m.each(function () {
                    n.call(this)
                })
            }, 0)
        }, 0), this
    }, i = null
}(Zepto),
function ($) {
    function triggerAndReturn(a, b, c) {
        var d = $.Event(b);
        return $(a).trigger(d, c), !d.defaultPrevented
    }
    function triggerGlobal(a, b, c, d) {
        if (a.global) return triggerAndReturn(b || document, c, d)
    }
    function ajaxStart(a) {
        a.global && $.active++ === 0 && triggerGlobal(a, null, "ajaxStart")
    }
    function ajaxStop(a) {
        a.global && !--$.active && triggerGlobal(a, null, "ajaxStop")
    }
    function ajaxBeforeSend(a, b) {
        var c = b.context;
        if (b.beforeSend.call(c, a, b) === !1 || triggerGlobal(b, c, "ajaxBeforeSend", [a, b]) === !1) return !1;
        triggerGlobal(b, c, "ajaxSend", [a, b])
    }
    function ajaxSuccess(a, b, c) {
        var d = c.context,
            e = "success";
        c.success.call(d, a, e, b), triggerGlobal(c, d, "ajaxSuccess", [b, c, a]), ajaxComplete(e, b, c)
    }
    function ajaxError(a, b, c, d) {
        var e = d.context;
        d.error.call(e, c, b, a), triggerGlobal(d, e, "ajaxError", [c, d, a]), ajaxComplete(b, c, d)
    }
    function ajaxComplete(a, b, c) {
        var d = c.context;
        c.complete.call(d, b, a), triggerGlobal(c, d, "ajaxComplete", [b, c]), ajaxStop(c)
    }
    function empty() {}
    function mimeToDataType(a) {
        return a && (a == htmlType ? "html" : a == jsonType ? "json" : scriptTypeRE.test(a) ? "script" : xmlTypeRE.test(a) && "xml") || "text"
    }
    function appendQuery(a, b) {
        return (a + "&" + b).replace(/[&?]{1,2}/, "?")
    }
    function serializeData(a) {
        isObject(a.data) && (a.data = $.param(a.data)), a.data && (!a.type || a.type.toUpperCase() == "GET") && (a.url = appendQuery(a.url, a.data))
    }
    function serialize(a, b, c, d) {
        var e = $.isArray(b);
        $.each(b, function (b, f) {
            d && (b = c ? d : d + "[" + (e ? "" : b) + "]"), !d && e ? a.add(f.name, f.value) : (c ? $.isArray(f) : isObject(f)) ? serialize(a, f, c, b) : a.add(b, f)
        })
    }
    var jsonpID = 0,
        isObject = $.isObject,
        document = window.document,
        key, name, rscript = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
        scriptTypeRE = /^(?:text|application)\/javascript/i,
        xmlTypeRE = /^(?:text|application)\/xml/i,
        jsonType = "application/json",
        htmlType = "text/html",
        blankRE = /^\s*$/;
    $.active = 0, $.ajaxJSONP = function (a) {
        var b = "jsonp" + ++jsonpID,
            c = document.createElement("script"),
            d = function () {
                $(c).remove(), b in window && (window[b] = empty), ajaxComplete("abort", e, a)
            }, e = {
                abort: d
            }, f;
        return a.error && (c.onerror = function () {
            e.abort(), a.error()
        }), window[b] = function (d) {
            clearTimeout(f), $(c).remove(), delete window[b], ajaxSuccess(d, e, a)
        }, serializeData(a), c.src = a.url.replace(/=\?/, "=" + b), $("head").append(c), a.timeout > 0 && (f = setTimeout(function () {
            e.abort(), ajaxComplete("timeout", e, a)
        }, a.timeout)), e
    }, $.ajaxSettings = {
        type: "GET",
        beforeSend: empty,
        success: empty,
        error: empty,
        complete: empty,
        context: null,
        global: !0,
        xhr: function () {
            return new window.XMLHttpRequest
        },
        accepts: {
            script: "text/javascript, application/javascript",
            json: jsonType,
            xml: "application/xml, text/xml",
            html: htmlType,
            text: "text/plain"
        },
        crossDomain: !1,
        timeout: 0
    }, $.ajax = function (options) {
        var settings = $.extend({}, options || {});
        for (key in $.ajaxSettings) settings[key] === undefined && (settings[key] = $.ajaxSettings[key]);
        ajaxStart(settings), settings.crossDomain || (settings.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(settings.url) && RegExp.$2 != window.location.host);
        var dataType = settings.dataType,
            hasPlaceholder = /=\?/.test(settings.url);
        if (dataType == "jsonp" || hasPlaceholder) return hasPlaceholder || (settings.url = appendQuery(settings.url, "callback=?")), $.ajaxJSONP(settings);
        settings.url || (settings.url = window.location.toString()), serializeData(settings);
        var mime = settings.accepts[dataType],
            baseHeaders = {}, protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol,
            xhr = $.ajaxSettings.xhr(),
            abortTimeout;
        settings.crossDomain || (baseHeaders["X-Requested-With"] = "XMLHttpRequest"), mime && (baseHeaders.Accept = mime, mime.indexOf(",") > -1 && (mime = mime.split(",", 2)[0]), xhr.overrideMimeType && xhr.overrideMimeType(mime));
        if (settings.contentType || settings.data && settings.type.toUpperCase() != "GET") baseHeaders["Content-Type"] = settings.contentType || "application/x-www-form-urlencoded";
        settings.headers = $.extend(baseHeaders, settings.headers || {}), xhr.onreadystatechange = function () {
            if (xhr.readyState == 4) {
                clearTimeout(abortTimeout);
                var result, error = !1;
                if (xhr.status >= 200 && xhr.status < 300 || xhr.status == 304 || xhr.status == 0 && protocol == "file:") {
                    dataType = dataType || mimeToDataType(xhr.getResponseHeader("content-type")), result = xhr.responseText;
                    try {
                        dataType == "script" ? (1, eval)(result) : dataType == "xml" ? result = xhr.responseXML : dataType == "json" && (result = blankRE.test(result) ? null : JSON.parse(result))
                    } catch (e) {
                        error = e
                    }
                    error ? ajaxError(error, "parsererror", xhr, settings) : ajaxSuccess(result, xhr, settings)
                } else ajaxError(null, "error", xhr, settings)
            }
        };
        var async = "async" in settings ? settings.async : !0;
        xhr.open(settings.type, settings.url, async);
        for (name in settings.headers) xhr.setRequestHeader(name, settings.headers[name]);
        return ajaxBeforeSend(xhr, settings) === !1 ? (xhr.abort(), !1) : (settings.timeout > 0 && (abortTimeout = setTimeout(function () {
            xhr.onreadystatechange = empty, xhr.abort(), ajaxError(null, "timeout", xhr, settings)
        }, settings.timeout)), xhr.send(settings.data ? settings.data : null), xhr)
    }, $.get = function (a, b) {
        return $.ajax({
            url: a,
            success: b
        })
    }, $.post = function (a, b, c, d) {
        return $.isFunction(b) && (d = d || c, c = b, b = null), $.ajax({
            type: "POST",
            url: a,
            data: b,
            success: c,
            dataType: d
        })
    }, $.getJSON = function (a, b) {
        return $.ajax({
            url: a,
            success: b,
            dataType: "json"
        })
    }, $.fn.load = function (a, b) {
        if (!this.length) return this;
        var c = this,
            d = a.split(/\s/),
            e;
        return d.length > 1 && (a = d[0], e = d[1]), $.get(a, function (a) {
            c.html(e ? $(document.createElement("div")).html(a.replace(rscript, "")).find(e).html() : a), b && b.call(c)
        }), this
    };
    var escape = encodeURIComponent;
    $.param = function (a, b) {
        var c = [];
        return c.add = function (a, b) {
            this.push(escape(a) + "=" + escape(b))
        }, serialize(c, a, b), c.join("&").replace("%20", "+")
    }
}(Zepto),
function (a) {
    a.fn.serializeArray = function () {
        var b = [],
            c;
        return a(Array.prototype.slice.call(this.get(0).elements)).each(function () {
            c = a(this);
            var d = c.attr("type");
            this.nodeName.toLowerCase() != "fieldset" && !this.disabled && d != "submit" && d != "reset" && d != "button" && (d != "radio" && d != "checkbox" || this.checked) && b.push({
                name: c.attr("name"),
                value: c.val()
            })
        }), b
    }, a.fn.serialize = function () {
        var a = [];
        return this.serializeArray().forEach(function (b) {
            a.push(encodeURIComponent(b.name) + "=" + encodeURIComponent(b.value))
        }), a.join("&")
    }, a.fn.submit = function (b) {
        if (b) this.bind("submit", b);
        else if (this.length) {
            var c = a.Event("submit");
            this.eq(0).trigger(c), c.defaultPrevented || this.get(0).submit()
        }
        return this
    }
}(Zepto),
function (a) {
    function d(a) {
        return "tagName" in a ? a : a.parentNode
    }
    function e(a, b, c, d) {
        var e = Math.abs(a - b),
            f = Math.abs(c - d);
        return e >= f ? a - b > 0 ? "Left" : "Right" : c - d > 0 ? "Up" : "Down"
    }
    function h() {
        g = null, b.last && (b.el.trigger("longTap"), b = {})
    }
    function i() {
        g && clearTimeout(g), g = null
    }
    var b = {}, c, f = 750,
        g;
    a(document).ready(function () {
        var j, k;
        a(document.body).bind("touchstart", function (e) {
            j = Date.now(), k = j - (b.last || j), b.el = a(d(e.touches[0].target)), c && clearTimeout(c), b.x1 = e.touches[0].pageX, b.y1 = e.touches[0].pageY, k > 0 && k <= 250 && (b.isDoubleTap = !0), b.last = j, g = setTimeout(h, f)
        }).bind("touchmove", function (a) {
            i(), b.x2 = a.touches[0].pageX, b.y2 = a.touches[0].pageY
        }).bind("touchend", function (a) {
            i(), b.isDoubleTap ? (b.el.trigger("doubleTap"), b = {}) : b.x2 && Math.abs(b.x1 - b.x2) > 30 || b.y2 && Math.abs(b.y1 - b.y2) > 30 ? (b.el.trigger("swipe") && b.el.trigger("swipe" + e(b.x1, b.x2, b.y1, b.y2)), b = {}) : "last" in b && (b.el.trigger("tap"), c = setTimeout(function () {
                c = null, b.el.trigger("singleTap"), b = {}
            }, 250))
        }).bind("touchcancel", function () {
            c && clearTimeout(c), g && clearTimeout(g), g = c = null, b = {}
        })
    }), ["swipe", "swipeLeft", "swipeRight", "swipeUp", "swipeDown", "doubleTap", "tap", "singleTap", "longTap"].forEach(function (b) {
        a.fn[b] = function (a) {
            return this.bind(b, a)
        }
    })
}(Zepto),
function () {
    function A(a, b, c) {
        if (a === b) return a !== 0 || 1 / a == 1 / b;
        if (a == null || b == null) return a === b;
        a._chain && (a = a._wrapped), b._chain && (b = b._wrapped);
        if (a.isEqual && w.isFunction(a.isEqual)) return a.isEqual(b);
        if (b.isEqual && w.isFunction(b.isEqual)) return b.isEqual(a);
        var d = i.call(a);
        if (d != i.call(b)) return !1;
        switch (d) {
        case "[object String]":
            return a == String(b);
        case "[object Number]":
            return a != +a ? b != +b : a == 0 ? 1 / a == 1 / b : a == +b;
        case "[object Date]":
        case "[object Boolean]":
            return +a == +b;
        case "[object RegExp]":
            return a.source == b.source && a.global == b.global && a.multiline == b.multiline && a.ignoreCase == b.ignoreCase
        }
        if (typeof a != "object" || typeof b != "object") return !1;
        var e = c.length;
        while (e--) if (c[e] == a) return !0;
        c.push(a);
        var f = 0,
            g = !0;
        if (d == "[object Array]") {
            f = a.length, g = f == b.length;
            if (g) while (f--) if (!(g = f in a == f in b && A(a[f], b[f], c))) break
        } else {
            if ("constructor" in a != "constructor" in b || a.constructor != b.constructor) return !1;
            for (var h in a) if (w.has(a, h)) {
                f++;
                if (!(g = w.has(b, h) && A(a[h], b[h], c))) break
            }
            if (g) {
                for (h in b) if (w.has(b, h) && !(f--)) break;
                g = !f
            }
        }
        return c.pop(), g
    }
    var a = this,
        b = a._,
        c = {}, d = Array.prototype,
        e = Object.prototype,
        f = Function.prototype,
        g = d.slice,
        h = d.unshift,
        i = e.toString,
        j = e.hasOwnProperty,
        k = d.forEach,
        l = d.map,
        m = d.reduce,
        n = d.reduceRight,
        o = d.filter,
        p = d.every,
        q = d.some,
        r = d.indexOf,
        s = d.lastIndexOf,
        t = Array.isArray,
        u = Object.keys,
        v = f.bind,
        w = function (a) {
            return new I(a)
        };
    typeof exports != "undefined" ? (typeof module != "undefined" && module.exports && (exports = module.exports = w), exports._ = w) : a._ = w, w.VERSION = "1.3.3";
    var x = w.each = w.forEach = function (a, b, d) {
        if (a == null) return;
        if (k && a.forEach === k) a.forEach(b, d);
        else if (a.length === +a.length) {
            for (var e = 0, f = a.length; e < f; e++) if (e in a && b.call(d, a[e], e, a) === c) return
        } else for (var g in a) if (w.has(a, g) && b.call(d, a[g], g, a) === c) return
    };
    w.map = w.collect = function (a, b, c) {
        var d = [];
        return a == null ? d : l && a.map === l ? a.map(b, c) : (x(a, function (a, e, f) {
            d[d.length] = b.call(c, a, e, f)
        }), a.length === +a.length && (d.length = a.length), d)
    }, w.reduce = w.foldl = w.inject = function (a, b, c, d) {
        var e = arguments.length > 2;
        a == null && (a = []);
        if (m && a.reduce === m) return d && (b = w.bind(b, d)), e ? a.reduce(b, c) : a.reduce(b);
        x(a, function (a, f, g) {
            e ? c = b.call(d, c, a, f, g) : (c = a, e = !0)
        });
        if (!e) throw new TypeError("Reduce of empty array with no initial value");
        return c
    }, w.reduceRight = w.foldr = function (a, b, c, d) {
        var e = arguments.length > 2;
        a == null && (a = []);
        if (n && a.reduceRight === n) return d && (b = w.bind(b, d)), e ? a.reduceRight(b, c) : a.reduceRight(b);
        var f = w.toArray(a).reverse();
        return d && !e && (b = w.bind(b, d)), e ? w.reduce(f, b, c, d) : w.reduce(f, b)
    }, w.find = w.detect = function (a, b, c) {
        var d;
        return y(a, function (a, e, f) {
            if (b.call(c, a, e, f)) return d = a, !0
        }), d
    }, w.filter = w.select = function (a, b, c) {
        var d = [];
        return a == null ? d : o && a.filter === o ? a.filter(b, c) : (x(a, function (a, e, f) {
            b.call(c, a, e, f) && (d[d.length] = a)
        }), d)
    }, w.reject = function (a, b, c) {
        var d = [];
        return a == null ? d : (x(a, function (a, e, f) {
            b.call(c, a, e, f) || (d[d.length] = a)
        }), d)
    }, w.every = w.all = function (a, b, d) {
        var e = !0;
        return a == null ? e : p && a.every === p ? a.every(b, d) : (x(a, function (a, f, g) {
            if (!(e = e && b.call(d, a, f, g))) return c
        }), !! e)
    };
    var y = w.some = w.any = function (a, b, d) {
        b || (b = w.identity);
        var e = !1;
        return a == null ? e : q && a.some === q ? a.some(b, d) : (x(a, function (a, f, g) {
            if (e || (e = b.call(d, a, f, g))) return c
        }), !! e)
    };
    w.include = w.contains = function (a, b) {
        var c = !1;
        return a == null ? c : r && a.indexOf === r ? a.indexOf(b) != -1 : (c = y(a, function (a) {
            return a === b
        }), c)
    }, w.invoke = function (a, b) {
        var c = g.call(arguments, 2);
        return w.map(a, function (a) {
            return (w.isFunction(b) ? b || a : a[b]).apply(a, c)
        })
    }, w.pluck = function (a, b) {
        return w.map(a, function (a) {
            return a[b]
        })
    }, w.max = function (a, b, c) {
        if (!b && w.isArray(a) && a[0] === +a[0]) return Math.max.apply(Math, a);
        if (!b && w.isEmpty(a)) return -Infinity;
        var d = {
            computed: -Infinity
        };
        return x(a, function (a, e, f) {
            var g = b ? b.call(c, a, e, f) : a;
            g >= d.computed && (d = {
                value: a,
                computed: g
            })
        }), d.value
    }, w.min = function (a, b, c) {
        if (!b && w.isArray(a) && a[0] === +a[0]) return Math.min.apply(Math, a);
        if (!b && w.isEmpty(a)) return Infinity;
        var d = {
            computed: Infinity
        };
        return x(a, function (a, e, f) {
            var g = b ? b.call(c, a, e, f) : a;
            g < d.computed && (d = {
                value: a,
                computed: g
            })
        }), d.value
    }, w.shuffle = function (a) {
        var b = [],
            c;
        return x(a, function (a, d, e) {
            c = Math.floor(Math.random() * (d + 1)), b[d] = b[c], b[c] = a
        }), b
    }, w.sortBy = function (a, b, c) {
        var d = w.isFunction(b) ? b : function (a) {
                return a[b]
            };
        return w.pluck(w.map(a, function (a, b, e) {
            return {
                value: a,
                criteria: d.call(c, a, b, e)
            }
        }).sort(function (a, b) {
            var c = a.criteria,
                d = b.criteria;
            return c === void 0 ? 1 : d === void 0 ? -1 : c < d ? -1 : c > d ? 1 : 0
        }), "value")
    }, w.groupBy = function (a, b) {
        var c = {}, d = w.isFunction(b) ? b : function (a) {
                return a[b]
            };
        return x(a, function (a, b) {
            var e = d(a, b);
            (c[e] || (c[e] = [])).push(a)
        }), c
    }, w.sortedIndex = function (a, b, c) {
        c || (c = w.identity);
        var d = 0,
            e = a.length;
        while (d < e) {
            var f = d + e >> 1;
            c(a[f]) < c(b) ? d = f + 1 : e = f
        }
        return d
    }, w.toArray = function (a) {
        return a ? w.isArray(a) ? g.call(a) : w.isArguments(a) ? g.call(a) : a.toArray && w.isFunction(a.toArray) ? a.toArray() : w.values(a) : []
    }, w.size = function (a) {
        return w.isArray(a) ? a.length : w.keys(a).length
    }, w.first = w.head = w.take = function (a, b, c) {
        return b != null && !c ? g.call(a, 0, b) : a[0]
    }, w.initial = function (a, b, c) {
        return g.call(a, 0, a.length - (b == null || c ? 1 : b))
    }, w.last = function (a, b, c) {
        return b != null && !c ? g.call(a, Math.max(a.length - b, 0)) : a[a.length - 1]
    }, w.rest = w.tail = function (a, b, c) {
        return g.call(a, b == null || c ? 1 : b)
    }, w.compact = function (a) {
        return w.filter(a, function (a) {
            return !!a
        })
    }, w.flatten = function (a, b) {
        return w.reduce(a, function (a, c) {
            return w.isArray(c) ? a.concat(b ? c : w.flatten(c)) : (a[a.length] = c, a)
        }, [])
    }, w.without = function (a) {
        return w.difference(a, g.call(arguments, 1))
    }, w.uniq = w.unique = function (a, b, c) {
        var d = c ? w.map(a, c) : a,
            e = [];
        return a.length < 3 && (b = !0), w.reduce(d, function (c, d, f) {
            if (b ? w.last(c) !== d || !c.length : !w.include(c, d)) c.push(d), e.push(a[f]);
            return c
        }, []), e
    }, w.union = function () {
        return w.uniq(w.flatten(arguments, !0))
    }, w.intersection = w.intersect = function (a) {
        var b = g.call(arguments, 1);
        return w.filter(w.uniq(a), function (a) {
            return w.every(b, function (b) {
                return w.indexOf(b, a) >= 0
            })
        })
    }, w.difference = function (a) {
        var b = w.flatten(g.call(arguments, 1), !0);
        return w.filter(a, function (a) {
            return !w.include(b, a)
        })
    }, w.zip = function () {
        var a = g.call(arguments),
            b = w.max(w.pluck(a, "length")),
            c = new Array(b);
        for (var d = 0; d < b; d++) c[d] = w.pluck(a, "" + d);
        return c
    }, w.indexOf = function (a, b, c) {
        if (a == null) return -1;
        var d, e;
        if (c) return d = w.sortedIndex(a, b), a[d] === b ? d : -1;
        if (r && a.indexOf === r) return a.indexOf(b);
        for (d = 0, e = a.length; d < e; d++) if (d in a && a[d] === b) return d;
        return -1
    }, w.lastIndexOf = function (a, b) {
        if (a == null) return -1;
        if (s && a.lastIndexOf === s) return a.lastIndexOf(b);
        var c = a.length;
        while (c--) if (c in a && a[c] === b) return c;
        return -1
    }, w.range = function (a, b, c) {
        arguments.length <= 1 && (b = a || 0, a = 0), c = arguments[2] || 1;
        var d = Math.max(Math.ceil((b - a) / c), 0),
            e = 0,
            f = new Array(d);
        while (e < d) f[e++] = a, a += c;
        return f
    };
    var z = function () {};
    w.bind = function (b, c) {
        var d, e;
        if (b.bind === v && v) return v.apply(b, g.call(arguments, 1));
        if (!w.isFunction(b)) throw new TypeError;
        return e = g.call(arguments, 2), d = function () {
            if (this instanceof d) {
                z.prototype = b.prototype;
                var a = new z,
                    f = b.apply(a, e.concat(g.call(arguments)));
                return Object(f) === f ? f : a
            }
            return b.apply(c, e.concat(g.call(arguments)))
        }
    }, w.bindAll = function (a) {
        var b = g.call(arguments, 1);
        return b.length == 0 && (b = w.functions(a)), x(b, function (b) {
            a[b] = w.bind(a[b], a)
        }), a
    }, w.memoize = function (a, b) {
        var c = {};
        return b || (b = w.identity),
        function () {
            var d = b.apply(this, arguments);
            return w.has(c, d) ? c[d] : c[d] = a.apply(this, arguments)
        }
    }, w.delay = function (a, b) {
        var c = g.call(arguments, 2);
        return setTimeout(function () {
            return a.apply(null, c)
        }, b)
    }, w.defer = function (a) {
        return w.delay.apply(w, [a, 1].concat(g.call(arguments, 1)))
    }, w.throttle = function (a, b) {
        var c, d, e, f, g, h, i = w.debounce(function () {
            g = f = !1
        }, b);
        return function () {
            c = this, d = arguments;
            var j = function () {
                e = null, g && a.apply(c, d), i()
            };
            return e || (e = setTimeout(j, b)), f ? g = !0 : h = a.apply(c, d), i(), f = !0, h
        }
    }, w.debounce = function (a, b, c) {
        var d;
        return function () {
            var e = this,
                f = arguments,
                g = function () {
                    d = null, c || a.apply(e, f)
                };
            c && !d && a.apply(e, f), clearTimeout(d), d = setTimeout(g, b)
        }
    }, w.once = function (a) {
        var b = !1,
            c;
        return function () {
            return b ? c : (b = !0, c = a.apply(this, arguments))
        }
    }, w.wrap = function (a, b) {
        return function () {
            var c = [a].concat(g.call(arguments, 0));
            return b.apply(this, c)
        }
    }, w.compose = function () {
        var a = arguments;
        return function () {
            var b = arguments;
            for (var c = a.length - 1; c >= 0; c--) b = [a[c].apply(this, b)];
            return b[0]
        }
    }, w.after = function (a, b) {
        return a <= 0 ? b() : function () {
            if (--a < 1) return b.apply(this, arguments)
        }
    }, w.keys = u || function (a) {
        if (a !== Object(a)) throw new TypeError("Invalid object");
        var b = [];
        for (var c in a) w.has(a, c) && (b[b.length] = c);
        return b
    }, w.values = function (a) {
        return w.map(a, w.identity)
    }, w.functions = w.methods = function (a) {
        var b = [];
        for (var c in a) w.isFunction(a[c]) && b.push(c);
        return b.sort()
    }, w.extend = function (a) {
        return x(g.call(arguments, 1), function (b) {
            for (var c in b) a[c] = b[c]
        }), a
    }, w.pick = function (a) {
        var b = {};
        return x(w.flatten(g.call(arguments, 1)), function (c) {
            c in a && (b[c] = a[c])
        }), b
    },
    w.defaults = function (a) {
        return x(g.call(arguments, 1), function (b) {
            for (var c in b) a[c] == null && (a[c] = b[c])
        }), a
    }, w.clone = function (a) {
        return w.isObject(a) ? w.isArray(a) ? a.slice() : w.extend({}, a) : a
    }, w.tap = function (a, b) {
        return b(a), a
    }, w.isEqual = function (a, b) {
        return A(a, b, [])
    }, w.isEmpty = function (a) {
        if (a == null) return !0;
        if (w.isArray(a) || w.isString(a)) return a.length === 0;
        for (var b in a) if (w.has(a, b)) return !1;
        return !0
    }, w.isElement = function (a) {
        return !!a && a.nodeType == 1
    }, w.isArray = t || function (a) {
        return i.call(a) == "[object Array]"
    }, w.isObject = function (a) {
        return a === Object(a)
    }, w.isArguments = function (a) {
        return i.call(a) == "[object Arguments]"
    }, w.isArguments(arguments) || (w.isArguments = function (a) {
        return !!a && !! w.has(a, "callee")
    }), w.isFunction = function (a) {
        return i.call(a) == "[object Function]"
    }, w.isString = function (a) {
        return i.call(a) == "[object String]"
    }, w.isNumber = function (a) {
        return i.call(a) == "[object Number]"
    }, w.isFinite = function (a) {
        return w.isNumber(a) && isFinite(a)
    }, w.isNaN = function (a) {
        return a !== a
    }, w.isBoolean = function (a) {
        return a === !0 || a === !1 || i.call(a) == "[object Boolean]"
    }, w.isDate = function (a) {
        return i.call(a) == "[object Date]"
    }, w.isRegExp = function (a) {
        return i.call(a) == "[object RegExp]"
    }, w.isNull = function (a) {
        return a === null
    }, w.isUndefined = function (a) {
        return a === void 0
    }, w.has = function (a, b) {
        return j.call(a, b)
    }, w.noConflict = function () {
        return a._ = b, this
    }, w.identity = function (a) {
        return a
    }, w.times = function (a, b, c) {
        for (var d = 0; d < a; d++) b.call(c, d)
    }, w.escape = function (a) {
        return ("" + a).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'").replace(/\//g, "/")
    }, w.result = function (a, b) {
        if (a == null) return null;
        var c = a[b];
        return w.isFunction(c) ? c.call(a) : c
    }, w.mixin = function (a) {
        x(w.functions(a), function (b) {
            K(b, w[b] = a[b])
        })
    };
    var B = 0;
    w.uniqueId = function (a) {
        var b = B++;
        return a ? a + b : b
    }, w.templateSettings = {
        evaluate: /<%([\s\S]+?)%>/g,
        interpolate: /<%=([\s\S]+?)%>/g,
        escape: /<%-([\s\S]+?)%>/g
    };
    var C = /.^/,
        D = {
            "\\": "\\",
            "'": "'",
            r: "\r",
            n: "\n",
            t: "	",
            u2028: "\u2028",
            u2029: "\u2029"
        };
    for (var E in D) D[D[E]] = E;
    var F = /\\|'|\r|\n|\t|\u2028|\u2029/g,
        G = /\\(\\|'|r|n|t|u2028|u2029)/g,
        H = function (a) {
            return a.replace(G, function (a, b) {
                return D[b]
            })
        };
    w.template = function (a, b, c) {
        c = w.defaults(c || {}, w.templateSettings);
        var d = "__p+='" + a.replace(F, function (a) {
            return "\\" + D[a]
        }).replace(c.escape || C, function (a, b) {
            return "'+\n_.escape(" + H(b) + ")+\n'"
        }).replace(c.interpolate || C, function (a, b) {
            return "'+\n(" + H(b) + ")+\n'"
        }).replace(c.evaluate || C, function (a, b) {
            return "';\n" + H(b) + "\n;__p+='"
        }) + "';\n";
        c.variable || (d = "with(obj||{}){\n" + d + "}\n"), d = "var __p='';var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n" + d + "return __p;\n";
        var e = new Function(c.variable || "obj", "_", d);
        if (b) return e(b, w);
        var f = function (a) {
            return e.call(this, a, w)
        };
        return f.source = "function(" + (c.variable || "obj") + "){\n" + d + "}", f
    }, w.chain = function (a) {
        return w(a).chain()
    };
    var I = function (a) {
        this._wrapped = a
    };
    w.prototype = I.prototype;
    var J = function (a, b) {
        return b ? w(a).chain() : a
    }, K = function (a, b) {
        I.prototype[a] = function () {
            var a = g.call(arguments);
            return h.call(a, this._wrapped), J(b.apply(w, a), this._chain)
        }
    };
    w.mixin(w), x(["pop", "push", "reverse", "shift", "sort", "splice", "unshift"], function (a) {
        var b = d[a];
        I.prototype[a] = function () {
            var c = this._wrapped;
            b.apply(c, arguments);
            var d = c.length;
            return (a == "shift" || a == "splice") && d === 0 && delete c[0], J(c, this._chain)
        }
    }), x(["concat", "join", "slice"], function (a) {
        var b = d[a];
        I.prototype[a] = function () {
            return J(b.apply(this._wrapped, arguments), this._chain)
        }
    }), I.prototype.chain = function () {
        return this._chain = !0, this
    }, I.prototype.value = function () {
        return this._wrapped
    }
}.call(this),
function () {
    var a = this,
        b = a.Backbone,
        c = Array.prototype.slice,
        d = Array.prototype.splice,
        e;
    typeof exports != "undefined" ? e = exports : e = a.Backbone = {}, e.VERSION = "0.9.2";
    var f = a._;
    !f && typeof require != "undefined" && (f = require("underscore"));
    var g = a.jQuery || a.Zepto || a.ender;
    e.setDomLibrary = function (a) {
        g = a
    }, e.noConflict = function () {
        return a.Backbone = b, this
    }, e.emulateHTTP = !1, e.emulateJSON = !1;
    var h = /\s+/,
        i = e.Events = {
            on: function (a, b, c) {
                var d, e, f, g, i;
                if (!b) return this;
                a = a.split(h), d = this._callbacks || (this._callbacks = {});
                while (e = a.shift()) i = d[e], f = i ? i.tail : {}, f.next = g = {}, f.context = c, f.callback = b, d[e] = {
                    tail: g,
                    next: i ? i.next : f
                };
                return this
            },
            off: function (a, b, c) {
                var d, e, g, i, j, k;
                if (!(e = this._callbacks)) return;
                if (!(a || b || c)) return delete this._callbacks, this;
                a = a ? a.split(h) : f.keys(e);
                while (d = a.shift()) {
                    g = e[d], delete e[d];
                    if (!g || !b && !c) continue;
                    i = g.tail;
                    while ((g = g.next) !== i) j = g.callback, k = g.context, (b && j !== b || c && k !== c) && this.on(d, j, k)
                }
                return this
            },
            trigger: function (a) {
                var b, d, e, f, g, i, j;
                if (!(e = this._callbacks)) return this;
                i = e.all, a = a.split(h), j = c.call(arguments, 1);
                while (b = a.shift()) {
                    if (d = e[b]) {
                        f = d.tail;
                        while ((d = d.next) !== f) d.callback.apply(d.context || this, j)
                    }
                    if (d = i) {
                        f = d.tail, g = [b].concat(j);
                        while ((d = d.next) !== f) d.callback.apply(d.context || this, g)
                    }
                }
                return this
            }
        };
    i.bind = i.on, i.unbind = i.off;
    var j = e.Model = function (a, b) {
        var c;
        a || (a = {}), b && b.parse && (a = this.parse(a));
        if (c = A(this, "defaults")) a = f.extend({}, c, a);
        b && b.collection && (this.collection = b.collection), this.attributes = {}, this._escapedAttributes = {}, this.cid = f.uniqueId("c"), this.changed = {}, this._silent = {}, this._pending = {}, this.set(a, {
            silent: !0
        }), this.changed = {}, this._silent = {}, this._pending = {}, this._previousAttributes = f.clone(this.attributes), this.initialize.apply(this, arguments)
    };
    f.extend(j.prototype, i, {
        changed: null,
        _silent: null,
        _pending: null,
        idAttribute: "id",
        initialize: function () {},
        toJSON: function (a) {
            return f.clone(this.attributes)
        },
        get: function (a) {
            return this.attributes[a]
        },
        escape: function (a) {
            var b;
            if (b = this._escapedAttributes[a]) return b;
            var c = this.get(a);
            return this._escapedAttributes[a] = f.escape(c == null ? "" : "" + c)
        },
        has: function (a) {
            return this.get(a) != null
        },
        set: function (a, b, c) {
            var d, e, g;
            f.isObject(a) || a == null ? (d = a, c = b) : (d = {}, d[a] = b), c || (c = {});
            if (!d) return this;
            d instanceof j && (d = d.attributes);
            if (c.unset) for (e in d) d[e] = void 0;
            if (!this._validate(d, c)) return !1;
            this.idAttribute in d && (this.id = d[this.idAttribute]);
            var h = c.changes = {}, i = this.attributes,
                k = this._escapedAttributes,
                l = this._previousAttributes || {};
            for (e in d) {
                g = d[e];
                if (!f.isEqual(i[e], g) || c.unset && f.has(i, e)) delete k[e], (c.silent ? this._silent : h)[e] = !0;
                c.unset ? delete i[e] : i[e] = g, !f.isEqual(l[e], g) || f.has(i, e) != f.has(l, e) ? (this.changed[e] = g, c.silent || (this._pending[e] = !0)) : (delete this.changed[e], delete this._pending[e])
            }
            return c.silent || this.change(c), this
        },
        unset: function (a, b) {
            return (b || (b = {})).unset = !0, this.set(a, null, b)
        },
        clear: function (a) {
            return (a || (a = {})).unset = !0, this.set(f.clone(this.attributes), a)
        },
        fetch: function (a) {
            a = a ? f.clone(a) : {};
            var b = this,
                c = a.success;
            return a.success = function (d, e, f) {
                if (!b.set(b.parse(d, f), a)) return !1;
                c && c(b, d)
            }, a.error = e.wrapError(a.error, b, a), (this.sync || e.sync).call(this, "read", this, a)
        },
        save: function (a, b, c) {
            var d, g;
            f.isObject(a) || a == null ? (d = a, c = b) : (d = {}, d[a] = b), c = c ? f.clone(c) : {};
            if (c.wait) {
                if (!this._validate(d, c)) return !1;
                g = f.clone(this.attributes)
            }
            var h = f.extend({}, c, {
                silent: !0
            });
            if (d && !this.set(d, c.wait ? h : c)) return !1;
            var i = this,
                j = c.success;
            c.success = function (a, b, e) {
                var g = i.parse(a, e);
                c.wait && (delete c.wait, g = f.extend(d || {}, g));
                if (!i.set(g, c)) return !1;
                j ? j(i, a) : i.trigger("sync", i, a, c)
            }, c.error = e.wrapError(c.error, i, c);
            var k = this.isNew() ? "create" : "update",
                l = (this.sync || e.sync).call(this, k, this, c);
            return c.wait && this.set(g, h), l
        },
        destroy: function (a) {
            a = a ? f.clone(a) : {};
            var b = this,
                c = a.success,
                d = function () {
                    b.trigger("destroy", b, b.collection, a)
                };
            if (this.isNew()) return d(), !1;
            a.success = function (e) {
                a.wait && d(), c ? c(b, e) : b.trigger("sync", b, e, a)
            }, a.error = e.wrapError(a.error, b, a);
            var g = (this.sync || e.sync).call(this, "delete", this, a);
            return a.wait || d(), g
        },
        url: function () {
            var a = A(this, "urlRoot") || A(this.collection, "url") || B();
            return this.isNew() ? a : a + (a.charAt(a.length - 1) == "/" ? "" : "/") + encodeURIComponent(this.id)
        },
        parse: function (a, b) {
            return a
        },
        clone: function () {
            return new this.constructor(this.attributes)
        },
        isNew: function () {
            return this.id == null
        },
        change: function (a) {
            a || (a = {});
            var b = this._changing;
            this._changing = !0;
            for (var c in this._silent) this._pending[c] = !0;
            var d = f.extend({}, a.changes, this._silent);
            this._silent = {};
            for (var c in d) this.trigger("change:" + c, this, this.get(c), a);
            if (b) return this;
            while (!f.isEmpty(this._pending)) {
                this._pending = {}, this.trigger("change", this, a);
                for (var c in this.changed) {
                    if (this._pending[c] || this._silent[c]) continue;
                    delete this.changed[c]
                }
                this._previousAttributes = f.clone(this.attributes)
            }
            return this._changing = !1, this
        },
        hasChanged: function (a) {
            return arguments.length ? f.has(this.changed, a) : !f.isEmpty(this.changed)
        },
        changedAttributes: function (a) {
            if (!a) return this.hasChanged() ? f.clone(this.changed) : !1;
            var b, c = !1,
                d = this._previousAttributes;
            for (var e in a) {
                if (f.isEqual(d[e], b = a[e])) continue;
                (c || (c = {}))[e] = b
            }
            return c
        },
        previous: function (a) {
            return !arguments.length || !this._previousAttributes ? null : this._previousAttributes[a]
        },
        previousAttributes: function () {
            return f.clone(this._previousAttributes)
        },
        isValid: function () {
            return !this.validate(this.attributes)
        },
        _validate: function (a, b) {
            if (b.silent || !this.validate) return !0;
            a = f.extend({}, this.attributes, a);
            var c = this.validate(a, b);
            return c ? (b && b.error ? b.error(this, c, b) : this.trigger("error", this, c, b), !1) : !0
        }
    });
    var k = e.Collection = function (a, b) {
        b || (b = {}), b.model && (this.model = b.model), b.comparator && (this.comparator = b.comparator), this._reset(), this.initialize.apply(this, arguments), a && this.reset(a, {
            silent: !0,
            parse: b.parse
        })
    };
    f.extend(k.prototype, i, {
        model: j,
        initialize: function () {},
        toJSON: function (a) {
            return this.map(function (b) {
                return b.toJSON(a)
            })
        },
        add: function (a, b) {
            var c, e, g, h, i, j, k = {}, l = {}, m = [];
            b || (b = {}), a = f.isArray(a) ? a.slice() : [a];
            for (c = 0, g = a.length; c < g; c++) {
                if (!(h = a[c] = this._prepareModel(a[c], b))) throw new Error("Can't add an invalid model to a collection");
                i = h.cid, j = h.id;
                if (k[i] || this._byCid[i] || j != null && (l[j] || this._byId[j])) {
                    m.push(c);
                    continue
                }
                k[i] = l[j] = h
            }
            c = m.length;
            while (c--) a.splice(m[c], 1);
            for (c = 0, g = a.length; c < g; c++)(h = a[c]).on("all", this._onModelEvent, this), this._byCid[h.cid] = h, h.id != null && (this._byId[h.id] = h);
            this.length += g, e = b.at != null ? b.at : this.models.length, d.apply(this.models, [e, 0].concat(a)), this.comparator && this.sort({
                silent: !0
            });
            if (b.silent) return this;
            for (c = 0, g = this.models.length; c < g; c++) {
                if (!k[(h = this.models[c]).cid]) continue;
                b.index = c, h.trigger("add", h, this, b)
            }
            return this
        },
        remove: function (a, b) {
            var c, d, e, g;
            b || (b = {}), a = f.isArray(a) ? a.slice() : [a];
            for (c = 0, d = a.length; c < d; c++) {
                g = this.getByCid(a[c]) || this.get(a[c]);
                if (!g) continue;
                delete this._byId[g.id], delete this._byCid[g.cid], e = this.indexOf(g), this.models.splice(e, 1), this.length--, b.silent || (b.index = e, g.trigger("remove", g, this, b)), this._removeReference(g)
            }
            return this
        },
        push: function (a, b) {
            return a = this._prepareModel(a, b), this.add(a, b), a
        },
        pop: function (a) {
            var b = this.at(this.length - 1);
            return this.remove(b, a), b
        },
        unshift: function (a, b) {
            return a = this._prepareModel(a, b), this.add(a, f.extend({
                at: 0
            }, b)), a
        },
        shift: function (a) {
            var b = this.at(0);
            return this.remove(b, a), b
        },
        get: function (a) {
            return a == null ? void 0 : this._byId[a.id != null ? a.id : a]
        },
        getByCid: function (a) {
            return a && this._byCid[a.cid || a]
        },
        at: function (a) {
            return this.models[a]
        },
        where: function (a) {
            return f.isEmpty(a) ? [] : this.filter(function (b) {
                for (var c in a) if (a[c] !== b.get(c)) return !1;
                return !0
            })
        },
        sort: function (a) {
            a || (a = {});
            if (!this.comparator) throw new Error("Cannot sort a set without a comparator");
            var b = f.bind(this.comparator, this);
            return this.comparator.length == 1 ? this.models = this.sortBy(b) : this.models.sort(b), a.silent || this.trigger("reset", this, a), this
        },
        pluck: function (a) {
            return f.map(this.models, function (b) {
                return b.get(a)
            })
        },
        reset: function (a, b) {
            a || (a = []), b || (b = {});
            for (var c = 0, d = this.models.length; c < d; c++) this._removeReference(this.models[c]);
            return this._reset(), this.add(a, f.extend({
                silent: !0
            }, b)), b.silent || this.trigger("reset", this, b), this
        },
        fetch: function (a) {
            a = a ? f.clone(a) : {}, a.parse === undefined && (a.parse = !0);
            var b = this,
                c = a.success;
            return a.success = function (d, e, f) {
                b[a.add ? "add" : "reset"](b.parse(d, f), a), c && c(b, d)
            }, a.error = e.wrapError(a.error, b, a), (this.sync || e.sync).call(this, "read", this, a)
        },
        create: function (a, b) {
            var c = this;
            b = b ? f.clone(b) : {}, a = this._prepareModel(a, b);
            if (!a) return !1;
            b.wait || c.add(a, b);
            var d = b.success;
            return b.success = function (e, f, g) {
                b.wait && c.add(e, b), d ? d(e, f) : e.trigger("sync", a, f, b)
            }, a.save(null, b), a
        },
        parse: function (a, b) {
            return a
        },
        chain: function () {
            return f(this.models).chain()
        },
        _reset: function (a) {
            this.length = 0, this.models = [], this._byId = {}, this._byCid = {}
        },
        _prepareModel: function (a, b) {
            b || (b = {});
            if (a instanceof j) a.collection || (a.collection = this);
            else {
                var c = a;
                b.collection = this, a = new this.model(c, b), a._validate(a.attributes, b) || (a = !1)
            }
            return a
        },
        _removeReference: function (a) {
            this == a.collection && delete a.collection, a.off("all", this._onModelEvent, this)
        },
        _onModelEvent: function (a, b, c, d) {
            if ((a == "add" || a == "remove") && c != this) return;
            a == "destroy" && this.remove(b, d), b && a === "change:" + b.idAttribute && (delete this._byId[b.previous(b.idAttribute)], this._byId[b.id] = b), this.trigger.apply(this, arguments)
        }
    });
    var l = ["forEach", "each", "map", "reduce", "reduceRight", "find", "detect", "filter", "select", "reject", "every", "all", "some", "any", "include", "contains", "invoke", "max", "min", "sortBy", "sortedIndex", "toArray", "size", "first", "initial", "rest", "last", "without", "indexOf", "shuffle", "lastIndexOf", "isEmpty", "groupBy"];
    f.each(l, function (a) {
        k.prototype[a] = function () {
            return f[a].apply(f, [this.models].concat(f.toArray(arguments)))
        }
    });
    var m = e.Router = function (a) {
        a || (a = {}), a.routes && (this.routes = a.routes), this._bindRoutes(), this.initialize.apply(this, arguments)
    }, n = /:\w+/g,
        o = /\*\w+/g,
        p = /[-[\]{}()+?.,\\^$|#\s]/g;
    f.extend(m.prototype, i, {
        initialize: function () {},
        route: function (a, b, c) {
            return e.history || (e.history = new q), f.isRegExp(a) || (a = this._routeToRegExp(a)), c || (c = this[b]), e.history.route(a, f.bind(function (d) {
                var f = this._extractParameters(a, d);
                c && c.apply(this, f), this.trigger.apply(this, ["route:" + b].concat(f)), e.history.trigger("route", this, b, f)
            }, this)), this
        },
        navigate: function (a, b) {
            e.history.navigate(a, b)
        },
        _bindRoutes: function () {
            if (!this.routes) return;
            var a = [];
            for (var b in this.routes) a.unshift([b, this.routes[b]]);
            for (var c = 0, d = a.length; c < d; c++) this.route(a[c][0], a[c][1], this[a[c][1]])
        },
        _routeToRegExp: function (a) {
            return a = a.replace(p, "\\$&").replace(n, "([^/]+)").replace(o, "(.*?)"), new RegExp("^" + a + "$")
        },
        _extractParameters: function (a, b) {
            return a.exec(b).slice(1)
        }
    });
    var q = e.History = function () {
        this.handlers = [], f.bindAll(this, "checkUrl")
    }, r = /^[#\/]/,
        s = /msie [\w.]+/;
    q.started = !1, f.extend(q.prototype, i, {
        interval: 50,
        getHash: function (a) {
            var b = a ? a.location : window.location,
                c = b.href.match(/#(.*)$/);
            return c ? c[1] : ""
        },
        getFragment: function (a, b) {
            if (a == null) if (this._hasPushState || b) {
                a = window.location.pathname;
                var c = window.location.search;
                c && (a += c)
            } else a = this.getHash();
            return a.indexOf(this.options.root) || (a = a.substr(this.options.root.length)), a.replace(r, "")
        },
        start: function (a) {
            if (q.started) throw new Error("Backbone.history has already been started");
            q.started = !0, this.options = f.extend({}, {
                root: "/"
            }, this.options, a), this._wantsHashChange = this.options.hashChange !== !1, this._wantsPushState = !! this.options.pushState, this._hasPushState = !! (this.options.pushState && window.history && window.history.pushState);
            var b = this.getFragment(),
                c = document.documentMode,
                d = s.exec(navigator.userAgent.toLowerCase()) && (!c || c <= 7);
            d && (this.iframe = g('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow, this.navigate(b)), this._hasPushState ? g(window).bind("popstate", this.checkUrl) : this._wantsHashChange && "onhashchange" in window && !d ? g(window).bind("hashchange", this.checkUrl) : this._wantsHashChange && (this._checkUrlInterval = setInterval(this.checkUrl, this.interval)), this.fragment = b;
            var e = window.location,
                h = e.pathname == this.options.root;
            if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !h) return this.fragment = this.getFragment(null, !0), window.location.replace(this.options.root + "#" + this.fragment), !0;
            this._wantsPushState && this._hasPushState && h && e.hash && (this.fragment = this.getHash().replace(r, ""), window.history.replaceState({}, document.title, e.protocol + "//" + e.host + this.options.root + this.fragment));
            if (!this.options.silent) return this.loadUrl()
        },
        stop: function () {
            g(window).unbind("popstate", this.checkUrl).unbind("hashchange", this.checkUrl), clearInterval(this._checkUrlInterval), q.started = !1
        },
        route: function (a, b) {
            this.handlers.unshift({
                route: a,
                callback: b
            })
        },
        checkUrl: function (a) {
            var b = this.getFragment();
            b == this.fragment && this.iframe && (b = this.getFragment(this.getHash(this.iframe)));
            if (b == this.fragment) return !1;
            this.iframe && this.navigate(b), this.loadUrl() || this.loadUrl(this.getHash())
        },
        loadUrl: function (a) {
            var b = this.fragment = this.getFragment(a),
                c = f.any(this.handlers, function (a) {
                    if (a.route.test(b)) return a.callback(b), !0
                });
            return c
        },
        navigate: function (a, b) {
            if (!q.started) return !1;
            if (!b || b === !0) b = {
                trigger: b
            };
            var c = (a || "").replace(r, "");
            if (this.fragment == c) return;
            this._hasPushState ? (c.indexOf(this.options.root) != 0 && (c = this.options.root + c), this.fragment = c, window.history[b.replace ? "replaceState" : "pushState"]({}, document.title, c)) : this._wantsHashChange ? (this.fragment = c, this._updateHash(window.location, c, b.replace), this.iframe && c != this.getFragment(this.getHash(this.iframe)) && (b.replace || this.iframe.document.open().close(), this._updateHash(this.iframe.location, c, b.replace))) : window.location.assign(this.options.root + a), b.trigger && this.loadUrl(a)
        },
        _updateHash: function (a, b, c) {
            c ? a.replace(a.toString().replace(/(javascript:|#).*$/, "") + "#" + b) : a.hash = b
        }
    });
    var t = e.View = function (a) {
        this.cid = f.uniqueId("view"), this._configure(a || {}), this._ensureElement(), this.initialize.apply(this, arguments), this.delegateEvents()
    }, u = /^(\S+)\s*(.*)$/,
        v = ["model", "collection", "el", "id", "attributes", "className", "tagName"];
    f.extend(t.prototype, i, {
        tagName: "div",
        $: function (a) {
            return this.$el.find(a)
        },
        initialize: function () {},
        render: function () {
            return this
        },
        remove: function () {
            return this.$el.remove(), this
        },
        make: function (a, b, c) {
            var d = document.createElement(a);
            return b && g(d).attr(b), c && g(d).html(c), d
        },
        setElement: function (a, b) {
            return this.$el && this.undelegateEvents(), this.$el = a instanceof g ? a : g(a), this.el = this.$el[0], b !== !1 && this.delegateEvents(), this
        },
        delegateEvents: function (a) {
            if (!a && !(a = A(this, "events"))) return;
            this.undelegateEvents();
            for (var b in a) {
                var c = a[b];
                f.isFunction(c) || (c = this[a[b]]);
                if (!c) throw new Error('Method "' + a[b] + '" does not exist');
                var d = b.match(u),
                    e = d[1],
                    g = d[2];
                c = f.bind(c, this), e += ".delegateEvents" + this.cid, g === "" ? this.$el.bind(e, c) : this.$el.delegate(g, e, c)
            }
        },
        undelegateEvents: function () {
            this.$el.unbind(".delegateEvents" + this.cid)
        },
        _configure: function (a) {
            this.options && (a = f.extend({}, this.options, a));
            for (var b = 0, c = v.length; b < c; b++) {
                var d = v[b];
                a[d] && (this[d] = a[d])
            }
            this.options = a
        },
        _ensureElement: function () {
            if (!this.el) {
                var a = A(this, "attributes") || {};
                this.id && (a.id = this.id), this.className && (a["class"] = this.className), this.setElement(this.make(this.tagName, a), !1)
            } else this.setElement(this.el, !1)
        }
    });
    var w = function (a, b) {
        var c = z(this, a, b);
        return c.extend = this.extend, c
    };
    j.extend = k.extend = m.extend = t.extend = w;
    var x = {
        create: "POST",
        update: "PUT",
        "delete": "DELETE",
        read: "GET"
    };
    e.sync = function (a, b, c) {
        var d = x[a];
        c || (c = {});
        var h = {
            type: d,
            dataType: "json"
        };
        return c.url || (h.url = A(b, "url") || B()), !c.data && b && (a == "create" || a == "update") && (h.contentType = "application/json", h.data = JSON.stringify(b.toJSON())), e.emulateJSON && (h.contentType = "application/x-www-form-urlencoded", h.data = h.data ? {
            model: h.data
        } : {}), e.emulateHTTP && (d === "PUT" || d === "DELETE") && (e.emulateJSON && (h.data._method = d), h.type = "POST", h.beforeSend = function (a) {
            a.setRequestHeader("X-HTTP-Method-Override", d)
        }), h.type !== "GET" && !e.emulateJSON && (h.processData = !1), g.ajax(f.extend(h, c))
    }, e.wrapError = function (a, b, c) {
        return function (d, e) {
            e = d === b ? e : d, a ? a(b, e, c) : b.trigger("error", b, e, c)
        }
    };
    var y = function () {}, z = function (a, b, c) {
        var d;
        return b && b.hasOwnProperty("constructor") ? d = b.constructor : d = function () {
            a.apply(this, arguments)
        }, f.extend(d, a), y.prototype = a.prototype, d.prototype = new y, b && f.extend(d.prototype, b), c && f.extend(d, c), d.prototype.constructor = d, d.__super__ = a.prototype, d
    }, A = function (a, b) {
        return !a || !a[b] ? null : f.isFunction(a[b]) ? a[b]() : a[b]
    }, B = function () {
        throw new Error('A "url" property or function must be specified')
    }
}.call(this), window.Swipe = function (a, b) {
    if (!a) return null;
    var c = this;
    this.options = b || {}, this.index = this.options.startSlide || 0, this.speed = this.options.speed || 300, this.callback = this.options.callback || function () {}, this.delay = this.options.auto || 0, this.preload = this.options.preload, this.lazyloadClass = this.options.lazyloadClass || "lazy", this.lazyloadDataAttr = this.options.lazyloadDataAttr || "original", this.verticalAlign = this.options.verticalAlign || "middle", this.container = a, this.element = this.container.children[0], this.container.style.overflow = "hidden", this.element.style.position = "relative", this.element.style.listStyle = "none", this.setup(), this.begin(), this.element.addEventListener && (this.element.addEventListener("touchstart", this, !1), this.element.addEventListener("touchmove", this, !1), this.element.addEventListener("touchend", this, !1), this.element.addEventListener("webkitTransitionEnd", this, !1), this.element.addEventListener("msTransitionEnd", this, !1), this.element.addEventListener("oTransitionEnd", this, !1), this.element.addEventListener("transitionend", this, !1), window.addEventListener("resize", this, !1))
}, Swipe.prototype = {
    setup: function () {
        this.slides = this.element.children, this.length = this.slides.length;
        if (this.length < 2) return null;
        this.width = this.container.getBoundingClientRect().width;
        if (!this.width) return null;
        this.container.style.visibility = "hidden", this.element.style.width = this.slides.length * this.width + "px";
        var a = this.slides.length;
        while (a--) {
            var b = this.slides[a];
            b.style.width = this.width + "px", b.style.display = "table-cell", b.style.verticalAlign = this.verticalAlign
        }
        this.slide(this.index, 0), this.container.style.visibility = "visible"
    },
    slide: function (a, b) {
        var c = this.element.style;
        b == undefined && (b = this.speed), c.webkitTransitionDuration = c.MozTransitionDuration = c.msTransitionDuration = c.OTransitionDuration = c.transitionDuration = b + "ms", c.left = -(a * this.width) + "px", this.index = a
    },
    getPos: function () {
        return this.index
    },
    prev: function (a) {
        this.delay = a || 0, clearTimeout(this.interval), this.index && this.slide(this.index - 1, this.speed)
    },
    next: function (a) {
        this.delay = a || 0, clearTimeout(this.interval), this.index < this.length - 1 ? this.slide(this.index + 1, this.speed) : this.slide(0, this.speed)
    },
    begin: function () {
        var a = this;
        this.interval = this.delay ? setTimeout(function () {
            a.next(a.delay)
        }, this.delay) : 0
    },
    stop: function () {
        this.delay = 0, clearTimeout(this.interval)
    },
    resume: function () {
        this.delay = this.options.auto || 0, this.begin()
    },
    load: function () {
        if (!this.preload) return;
        var a = this.slides[this.index];
        a.getAttribute("loaded") || this._loadImages(a), this.index < this.length - 1 && (a = this.slides[this.index + 1], a.getAttribute("loaded") || this._loadImages(a))
    },
    _loadImages: function (a) {
        var b = a.querySelectorAll("img." + this.lazyloadClass);
        for (var c = 0; c < b.length; c++)(function () {
            var a = c,
                d = new Image;
            d.onload = function () {
                b[a].parentNode.replaceChild(this, b[a])
            }, d.src = b[c].getAttribute("data-" + this.lazyloadDataAttr)
        }).call(this);
        a.setAttribute("loaded", !0)
    },
    handleEvent: function (a) {
        switch (a.type) {
        case "touchstart":
            this.onTouchStart(a);
            break;
        case "touchmove":
            this.onTouchMove(a);
            break;
        case "touchend":
            this.onTouchEnd(a);
            break;
        case "webkitTransitionEnd":
        case "msTransitionEnd":
        case "oTransitionEnd":
        case "transitionend":
            this.transitionEnd(a);
            break;
        case "resize":
            this.setup()
        }
    },
    transitionEnd: function (a) {
        this.preload && this.load(), this.delay && this.begin(), this.callback(a, this.index, this.slides[this.index])
    },
    onTouchStart: function (a) {
        this.start = {
            pageX: a.touches[0].pageX,
            pageY: a.touches[0].pageY,
            time: Number(new Date)
        }, this.isScrolling = undefined, this.deltaX = 0, this.element.style.MozTransitionDuration = this.element.style.webkitTransitionDuration = 0
    },
    onTouchMove: function (a) {
        if (a.touches.length > 1 || a.scale && a.scale !== 1) return;
        this.deltaX = a.touches[0].pageX - this.start.pageX, typeof this.isScrolling == "undefined" && (this.isScrolling = !! (this.isScrolling || Math.abs(this.deltaX) < Math.abs(a.touches[0].pageY - this.start.pageY))), this.isScrolling || (a.preventDefault(), clearTimeout(this.interval), this.deltaX = this.deltaX / (!this.index && this.deltaX > 0 || this.index == this.length - 1 && this.deltaX < 0 ? Math.abs(this.deltaX) / this.width + 1 : 1), this.element.style.left = this.deltaX - this.index * this.width + "px")
    },
    onTouchEnd: function (a) {
        var b = Number(new Date) - this.start.time < 250 && Math.abs(this.deltaX) > 20 || Math.abs(this.deltaX) > this.width / 2,
            c = !this.index && this.deltaX > 0 || this.index == this.length - 1 && this.deltaX < 0;
        this.isScrolling || this.slide(this.index + (b && !c ? this.deltaX < 0 ? 1 : -1 : 0), this.speed)
    }
}, window.App = window.App || {}, App.version = "0.9.0", App.fadeInTime = 180, App.errorMessage = "网络连接失败,请稍后重试", App.cartIsFullMsg = "购物车已满,请进行删除整理", App.addCartSuccMsg = "加入购物车成功!", App.addFavSuccMsg = "加入收藏夹成功!", App.defaultImage = "http://img02.taobaocdn.com/tps/i2/T1BJ9WXl4eXXXXXXXX-200-200.jpg", App.run = function (a) {
    if (a == null) throw "App#run -- no command error";
    if (!/\w+:\w+/.test(a)) throw "App#run -- invalid command: " + a;
    var b = a.split(":")[0],
        c = App[b],
        d = a.split(":")[1];
    if (c == null) throw "App#run -- App." + b + " not defined";
    if (c[d] == null) throw "App#run -- App." + b + " has no such method: " + d;
    c[d].apply(c, [].slice.call(arguments, 1))
}, App.convertImages = function (a, b) {
    function c(a, b) {
        return a.search(/\d+x\d+\.jpg/) > -1 || a.match(/jpg$/) && a.match(/jpg/g).length > 1 ? a : a.search(/taobao\.com/) > -1 && a.search(/jpg$/) > -1 ? a + "_" + b + ".jpg" : a
    }
    if ({}.toString.call(a) == "[object String]") return c(a, b);
    if ({}.toString.call(a) == "[object Array]") {
        var d, e = [];
        for (var f = 0; f < a.length; f++) e.push(c(a[f], b));
        return e
    }
    throw "Invalid arguments"
}, App.logUserAction = function (a) {
    $.ajax({
        url: App.data.logAjaxUrl,
        data: {
            pds: a,
            t: +(new Date)
        }
    })
}, App.tabsFocus = function () {
    window.scroll(0, $("#tabs").offset().top)
},
function (a) {
    a.ajaxSettings.timeout = 8e3
}(Zepto), window.H5 || (window.H5 = {}), H5.creditToRank = function (a) {
    var b = 0;
    return a >= 4 && a <= 10 ? b = 1 : a >= 11 && a <= 40 ? b = 2 : a >= 41 && a <= 90 ? b = 3 : a >= 91 && a <= 150 ? b = 4 : a >= 151 && a <= 250 ? b = 5 : a >= 251 && a <= 500 ? b = 6 : a >= 501 && a <= 1e3 ? b = 7 : a >= 1001 && a <= 2e3 ? b = 8 : a >= 2001 && a <= 5e3 ? b = 9 : a >= 5001 && a <= 1e4 ? b = 10 : a >= 10001 && a <= 2e4 ? b = 11 : a >= 20001 && a <= 5e4 ? b = 12 : a >= 50001 && a <= 1e5 ? b = 13 : a >= 100001 && a <= 2e5 ? b = 14 : a >= 200001 && a <= 5e5 ? b = 15 : a >= 500001 && a <= 1e6 ? b = 16 : a >= 1000001 && a <= 2e6 ? b = 17 : a >= 2000001 && a <= 5e6 ? b = 18 : a >= 5000001 && a <= 1e7 ? b = 19 : a >= 10000001 && (b = 20), b
},
function (a) {
    a.swipeTopTouch = function (b) {
        var c = {
            el: null,
            direction: "y",
            limitDirection: "",
            limitLen: 20,
            noTouchFun: null,
            touchmove: null,
            touchend: null
        };
        a.extend(c, b);
        if (!c.el) return;
        this.el = a(c.el)[0], this.op = c, this.isAndroid = /android/gi.test(navigator.appVersion), this._isTouch = "ontouchstart" in window, this._touchstart = "ontouchstart", this._touchmove = "ontouchmove", this._touchend = "ontouchend", this._isTouch || (this._touchstart = "onmousedown", this._touchmove = "onmousemove", this._touchend = "onmouseup"), this.init()
    }, a.extend(a.swipeTopTouch.prototype, {
        init: function () {
            var a = this;
            a.el[a._touchstart] = function (b) {
                a.start.call(a, b)
            }
        },
        getXY: function (a) {
            var b = this._isTouch ? a.touches[0] : a;
            return {
                x: b.pageX,
                y: b.pageY
            }
        },
        start: function (a) {
            var b = this;
            b._coord = b.getXY(a), b.el[b._touchmove] = function (a) {
                b.move.call(b, a)
            }, b.el[b._touchend] = function (a) {
                b.end.call(b, a)
            }
        },
        move: function (a) {
            var b = this,
                c = b.op,
                d = c.direction.toLowerCase();
            b._moveCoord = b.getXY(a);
            var e = b._moveCoord.x - b._coord.x,
                f = b._moveCoord.y - b._coord.y;
            d == "x" ? Math.abs(e) - Math.abs(f) > 10 && (a.preventDefault(), b._movestart = !0) : d == "y" && Math.abs(f) - Math.abs(e) > 10 && (a.preventDefault(), b._movestart = !0, c.touchmove && c.touchmove())
        },
        end: function (a) {
            var b = this,
                c = b.op,
                d = c.direction.toLowerCase(),
                e = c.limitDirection.toLowerCase(),
                f = c.limitLen,
                g, h = !1;
            if (b._movestart) {
                a.preventDefault(), g = d == "x" ? b._moveCoord.x - b._coord.x : b._moveCoord.y - b._coord.y;
                switch (e) {
                case "down":
                case "left":
                    g > f && (h = !0);
                    break;
                case "up":
                case "right":
                    g < -f && (h = !0);
                    break;
                default:
                    Math.abs(g) > f && (h = !0)
                }
                h && c.touchend && c.touchend(a), b._movestart = !1, g = null, h = null
            } else c.noTouchFun && (a.preventDefault(), setTimeout(c.noTouchFun, b.isAndroid ? 500 : 0));
            b.el[b._touchmove] = null, b.el[b._touchend] = null, b._coord = {}, b._moveCoord = {}
        }
    }), a.swipeTop = function (b, c) {
        var d = document,
            e = {
                isInit: !0,
                wrap: "",
                topEl: "ttype",
                header: "header",
                shade: "J_shade",
                hShade: "h-Shade",
                scrollArr: null,
                favScroll: null,
                swipeTopGap: 60,
                ease: "ease",
                easetime: 500,
                opacity: .1,
                isSwipeDown: !1,
                toptabHeight: 50,
                headerHeight: 50,
                surplusHeight: 80
            };
        b && a.extend(e, b), c && a.extend(this, c), this.op = e, this.wrap = d.getElementById(e.wrap);
        var f = d.getElementById(e.topEl);
        this.swipeTop = f ? a(f) : null, this.header = d.getElementById(e.header), this.shade = a(d.getElementById(e.shade)), this.hShade = a(d.getElementById(e.hShade)), this.wrap.style.cssText = "position:relative";
        var g = a(this.header);
        divt = a(document.createElement("div")), divt.css({
            height: e.headerHeight
        }), g.after(divt), this.notop = !1, this.swipeTop ? (g.addClass("header"), g.appendTo(this.swipeTop)) : (this.swipeTop = g, this.swipeTop.css({
            position: "absolute",
            "z-index": 118
        }), this.notop = !0), this.topCache = {
            isSlip: 0,
            isShow: !1,
            shadeShow: !1,
            isScroll: !1
        }, e.isInit && this.init()
    }, a.extend(a.swipeTop.prototype, {
        setOp: function (a, b) {
            if (typeof a == "string") this.op[a] = b;
            else for (var c in a) this.op[c] = a[c]
        },
        createShade: function () {
            var b = this,
                c = b.op,
                d = b.swipeTop,
                e = b.header,
                f, g, h = document;
            h.getElementById(c.shade) || (f = a(h.createElement("div")), f.attr("id", "J_shade"), f.addClass("J_shade"), f.appendTo(d.parent()), b.shade = f, b.shadeTouch(f)), !h.getElementById(c.hShade) && !b.notop && (g = a(h.createElement("div")), g.attr("id", "h-Shade"), g.addClass("h_shade"), g.appendTo(e), g.css("height", c.headerHeight), b.hShade = g, b.shadeTouch(g))
        },
        init: function (b) {
            var c = this,
                d = c.op;
            d.favScroll = b || null, c.initHeight(1), c.triggerEvent();
            var e = "onorientationchange" in window ? "orientationchange" : "resize",
                f = /android/gi.test(navigator.appVersion);
            d.scrollArr && window.addEventListener(e, function () {
                setTimeout(function () {
                    c.initHeight();
                    if (d.scrollArr.length > 0) {
                        var b = null;
                        a(d.scrollArr).each(function (d, e) {
                            b = a("#" + e), b.hasClass("none") ? b.parent().prev().find("li:not(.sel)").removeAttr("ajax") : c["tab" + d] && c["tab" + d].refresh()
                        })
                    }
                }, f ? 500 : 0)
            }, !1), document.addEventListener("touchmove", function (a) {
                var b = document.body.getAttribute("bounce");
                if (b) {
                    a.preventDefault();
                    return
                }
            }, !1)
        },
        initHeight: function (b) {
            var c = this,
                d = c.op,
                e = c.swipeTop,
                f = a(window),
                g = c.getScroll(),
                h = c.topCache,
                i = h.isShow,
                j = d.toptabHeight,
                k = d.headerHeight,
                l = d.surplusHeight,
                m = f.height();
            m = m > 380 ? 380 : m;
            var n = m - l + k,
                o = this.ntop = -n,
                p = this.nstep = n;
            c.notop && (n = k, o = this.ntop = -50, this.op.isSwipeDown = !1);
            var q = {
                height: n,
                width: "100%"
            }, r = o,
                s = k,
                t = Math.min(k, g);
            b || (g > 0 && h.isSlip == 1 && (s += t, g > k && (r += g - k)), i && (s = p + t)), q.top = r, q["-webkit-transform"] = "translate(0," + s + "px)", e.css(q)
        },
        showShade: function () {
            var a = this,
                b = a.hShade;
            a.topCache.shadeShow || a.showSingleShade(), b[0].style.cssText = "opacity:" + a.op.opacity + ";display:block"
        },
        showSingleShade: function () {
            var a = this,
                b = this.shade;
            b[0].style.cssText = "opacity:" + a.op.opacity + ";display:block"
        },
        editCategory: function (b) {
            var c = this,
                d = a(c.header.firstElementChild);
            if (d.length == 0) return;
            b == "remove" ? d.removeClass("c-inav-down") : b == "add" && d.addClass("c-inav-down")
        },
        editScroll: function (a) {
            var b = this,
                c = b.op.favScroll;
            if (!c) {
                var d = document.body;
                a ? d.removeAttribute("bounce") : d.setAttribute("bounce", 1);
                return
            }
            c.enabled = a
        },
        getScroll: function (a) {
            var b = this,
                c = b.op.favScroll,
                d = 0;
            return c ? d = c.y : d = document.body.scrollTop, d = a || d, Math.abs(d)
        },
        swipeAni: function (a, b) {
            var c = this,
                d = c.op,
                e = c.swipeTop,
                f = a || 0;
            f += "px", e.animate({
                translateY: f
            }, d.easetime, d.ease, function () {
                b && b.call(this)
            })
        },
        hidetab: function (b) {
            var c = this,
                d = c.op;
            if (c.tab0 && c.tabBody && d.scrollArr) {
                var e = c.tabBody.index,
                    f = a("#" + d.scrollArr[e]);
                if (b) f.removeClass("none");
                else {
                    var g = setTimeout(function () {
                        f.addClass("none")
                    }, 0);
                    clearTimeout(g)
                }
            }
        },
        hideTop: function (a) {
            var b = this,
                c = b.op,
                d = b.wrap,
                e = b.swipeTop,
                f = b.shade,
                g = b.hShade,
                h = b.ntop,
                i = c.headerHeight,
                j = parseInt(e.css("top"), 10) - h + i,
                k = b.topCache;
            a && a == "noAnimate" ? (e.css({
                "-webkit-transform": "translate(0," + i + "px)",
                top: h
            }), b.hidetab()) : j > i ? e.width() == 0 ? e.css({
                "-webkit-transform": "translate(0," + i + "px)",
                top: h
            }) : b.swipeAni(i, function () {
                this.style.top = h + "px", b.hidetab()
            }) : b.swipeAni(i, function () {
                b.hidetab()
            }), f[0].style.display = "none", b.editScroll(!0), k.isSlip = 2, k.shadeShow || (g[0].style.display = "none", k.isShow = !1, b.editCategory("remove")), k.shadeShow = !1;
            if (a && a == "taojia") return;
            var l = c.taojia;
            l && (l.st() == 2 ? l.circlHide() : l.taojiaShow())
        },
        showTop: function (a, b) {
            var c = document,
                d = this,
                e = d.op,
                f = d.wrap,
                g = d.swipeTop,
                h = d.ntop,
                i = d.topCache,
                j = i.isShow,
                k = a && typeof a == "number" ? !0 : !1,
                l = d.nstep;
            d.createShade();
            if (!j) {
                d.editScroll(!1);
                var m = d.getScroll(a),
                    n = e.headerHeight,
                    o = Math.min(e.headerHeight, m);
                k && (l -= n), d.swipeAni(l + o), i.isShow = !0, d.editCategory("add"), d.showShade(), d.swipeDown && d.swipeDown(b), e.taojia && e.taojia.taojiaHide(), i.shadeShow && (i.shadeShow = !1), d.hidetab(!0)
            } else d.hideTop()
        },
        tapDown: function () {
            var a = this,
                b = a.swipeTop,
                c = a.topCache,
                d = a.op,
                e = a.ntop,
                f = d.headerHeight,
                g = a.header;
            if (c.isScroll) return;
            var h = a.getScroll(),
                i = h + e,
                j = i - f,
                k = f + Math.min(f, h);
            if (c.isSlip == 1) {
                a.hideTop("taojia");
                return
            }
            i > e && h > f && b.css("top", j), i > e && a.swipeAni(k), a.createShade(), a.showSingleShade(), c.isSlip = 1, c.shadeShow = !0, a.editScroll(!1)
        },
        shadeTouch: function (b) {
            if (!b) return;
            var c = this;
            new a.swipeTopTouch({
                el: b,
                limitDirection: "up",
                noTouchFun: function () {
                    c.hideTop()
                },
                touchend: function () {
                    c.hideTop()
                }
            })
        },
        triggerEvent: function () {
            var a = this;
            a.tiggerFunc && a.tiggerFunc()
        }
    })
}(Zepto),
function (a) {
    window.H5 = window.H5 || {}, H5.TaoPlus = {
        initialize: function (b) {
            var c = this;
            c._opt = b || {};
            var d = {
                init: function () {
                    var a = "m",
                        b = location.host;
                    return b.match("m.(taobao|tmall|etao|alibaba|alipay|aliyun)") || (b == "localhost" || b.match("(?:.*\\.)?waptest\\.(taobao|tmall|etao|alibaba|alipay|aliyun)\\.com.*") ? a = "waptest" : b.match("(?:.*\\.)?wapa\\.(taobao|tmall|etao|alibaba|alipay|aliyun)\\.com.*") && (a = "wapa")), a
                }
            };
            window.navigator.userAgent.indexOf("Chrome") != -1 && a("body > div").addClass("chrome");
            var e = function () {
                var a = location.search,
                    b = "ttid=",
                    c, d = /ttid=(\w*)(?: |&|$)/;
                d.test(a) && (c = RegExp.$1);
                var e = c && "&" + b + c || "";
                return e
            }, f = {
                _css: function () {
                    window.navigator.userAgent.indexOf("UC") != -1 ? a("head").append('<link rel="stylesheet" type="text/css" href="http://a.tbcdn.cn/mw/base/styles/component/taoplus/css/taoplus_uc.css" />') : a("head").append('<link rel="stylesheet" type="text/css" href="http://a.tbcdn.cn/mw/base/styles/component/taoplus/css/taoplus.css" />')
                },
                _generate: function () {
                    var b = d.init(),
                        c = {};
                    c.s = "http://" + b + ".taobao.com/channel/act/sale/searchlist.html?pds=search%23h%23taojia" + e(), c.cart = "http://cart." + b + ".taobao.com/my_cart.htm?pds=cart%23h%23taojia" + e(), c.my = "http://my." + b + ".taobao.com/my_taobao.htm?pds=mytaobao%23h%23taojia" + e(), c.im = "http://im." + b + ".taobao.com/ww/ad_ww_lately_contacts.htm?pds=ww%23h%23taojia" + e(), c.logis = "http://tm." + b + ".taobao.com/order_list.htm?statusId=5&pds=wuliu%23h%23taojia" + e(), c.more = "http://" + b + ".taobao.com/channel/chn/mobile/application.html?pds=apply%23h%23taojia" + e();
                    var f = '<div class="taoplus" id="J_Taojia"><div class="taoplus-btn on" data-time="0"><div class="taoplus-btn-iconbox"><ul><li>t</li><li id="J_btnmsg">w</li><li>t</li></ul></div></div><div class="taoplus-main" data-total="" data-totalNew="" ><div class="circlbg"><span>o</span></div><ul class="icons"><li class="search"><a data-url="' + c.s + '">s</a><span class="bg"><span>p</span></span></li><li class="car"><a data-url="' + c.cart + '">u</a><span class="bg"><span>p</span></span></li><li class="individ"><a data-url="' + c.my + '">r</a><span class="bg">p</span></li><li class="ww"><a data-url="' + c.im + '">w</a><span class="bg">p</span></li><li class="logis"><a data-url="' + c.logis + '">q</a><span class="bg">p</span></li><li class="more"><a data-url="' + c.more + '">ooo</a><span class="bg">p</span></li></ul><div class="biglogo"><a data-url="http://' + b + ".taobao.com?pds=home%23h%23taojia" + e() + '">x</a><span class="biglogobg"></span></div></div></div>';
                    a("body > div").append(f)
                }
            };
            f._css(), f._generate();
            var g = {
                btn: a("#J_Taojia .taoplus-btn"),
                main: a("#J_Taojia .taoplus-main"),
                _browser: function () {
                    var a = navigator.userAgent,
                        b = ["iPhone OS ", "Android "],
                        c = {
                            iphone: !1,
                            adnroid: !1
                        }, d = "",
                        e = [];
                    for (var f = 0; f < b.length; f++) {
                        var g = a.indexOf(b[f]);
                        if (g > -1) {
                            switch (f) {
                            case 0:
                                c.iphone = !0;
                                break;
                            case 1:
                                c.adnroid = !0
                            }
                            var h = b[f].length;
                            d = a.substr(g + h, 6), e = d.split(/_|\./)
                        }
                    }
                    return {
                        iphone: c.iphone,
                        android: c.adnroid,
                        version: e
                    }
                }(),
                _slide: function () {
                    function b(a) {
                        g.btn.css({
                            opacity: "1",
                            "-webkit-transition": "opacity 3s linear "
                        })
                    }
                    function c(a) {
                        g.btn.css({
                            opacity: "0",
                            top: window.innerHeight + window.scrollY - 80 + "px",
                            "-webkit-transition": "none"
                        })
                    }
                    g._browser.iphone && a("body > div").addClass("ios");
                    if (g._browser.iphone && Number(g._browser.version[0] + "." + g._browser.version[1]) < 5 || g._browser.android && Number(g._browser.version[0] + "." + g._browser.version[1]) <= 2.1) window.addEventListener("scroll", b, !1), document.addEventListener("touchmove", c, !1)
                },
                _maintop: function () {
                    function b() {
                        g.main.css({
                            top: window.innerHeight + window.scrollY - 230
                        })
                    }
                    b(), a(window).bind("scroll touchend resize", function () {
                        b()
                    })
                },
                _msg: function () {
                    function f() {
                        a("#J_btnmsg").removeClass("logisaction").addClass("wwaction"), a("#J_btnmsg").html("w"), a("#J_Taojia").find(".taoplus-btn-iconbox ul").addClass("btnact")
                    }
                    function g() {
                        a("#J_btnmsg").removeClass("wwaction").addClass("wwaction"), a("#J_btnmsg").html("q"), a("#J_Taojia").find(".taoplus-btn-iconbox ul").addClass("btnact")
                    }
                    var b = d.init(),
                        e = "http://" + b + ".taobao.com/indexHeaderAjax.htm?callback=?";
                    a.ajax({
                        url: e,
                        type: "post",
                        dataType: "json",
                        success: function (b) {
                            var d = b.result,
                                e = b.totalMsgCount,
                                h = b.taobaoRadioMsgCount,
                                i = b.wwMsgCout,
                                j = b.logisticsMsgCount;
                            if (d) {
                                var k = a("#J_Taojia"),
                                    l = k.find(".ww a"),
                                    m = k.find(".logis a");
                                i > 0 && (i >= 10 ? l.append('<strong class="num">N</strong>') : l.append('<strong class="num">' + i + "</strong>")), j && (j >= 10 ? m.append('<strong class="num">N</strong>') : m.append('<strong class="num">' + j + "</strong>"));
                                var n = document.cookie;
                                if (!n || n.match(/wwmsg=\d+/) == null) document.cookie = "wwmsg=0&", document.cookie = "logismsg=0&", n = document.cookie;
                                var o = Number(n.match(/wwmsg=\d+/)[0].split("=")[1]),
                                    p = Number(n.match(/logismsg=\d+/)[0].split("=")[1]);
                                o != i && p == j && (document.cookie = "wwmsg=" + i + "&", f(), c.getmsg()), p != j && o == i && (document.cookie = "logismsg=" + j + "&", g(), c.getmsg());
                                if (p != j && o != i) {
                                    var q = null;
                                    document.cookie = "logismsg=" + j + "&", g(), c.getmsg(), q = setTimeout(function () {
                                        document.cookie = "wwmsg=" + i + "&", f(), c.getmsg()
                                    }, 6e3)
                                }
                            }
                        },
                        error: function (a, b) {}
                    })
                }
            };
            g._slide(), g._maintop(), g._msg(), c._switched()
        },
        getmsg: function () {
            var b = a("#J_Taojia").find(".taoplus-btn-iconbox ul"),
                c = a("#J_btnmsg"),
                d = null;
            d = setInterval(function () {
                var a = b[0].offsetLeft;
                b.addClass("btnact"), a <= -96 ? (clearInterval(d), b.removeClass("btnact"), b.css("left", 0)) : b.css("left", a - 48)
            }, 2e3)
        },
        shopcar: function (b) {
            var c = b,
                b = '<div class="taoplus-goimg"><img src="' + c + '"/></div>',
                d = a("#J_Taojia"),
                e = '<div class="taoplus-gocar">u</div>',
                f = null;
            a("#J_btnmsg").html("u"), that.getmsg(), d.append(b, e), f = setTimeout(function () {
                a(".taoplus-gocar").css({
                    right: "250px",
                    opacity: "0"
                })
            }, 1800)
        },
        _switched: function () {
            var b = this,
                c = {
                    taojiaTouch: a("#J_Taojia").find(".taoplus-btn"),
                    taojiaLogo: a("#J_Taojia").find(".biglogo").find("a"),
                    taojiaIcons: a("#J_Taojia").find(".icons").find("a"),
                    btn: function () {
                        c.taojiaTouch.click(function () {
                            var c = (new Date).getTime(),
                                d = Number(a(this).attr("data-time"));
                            c - d >= 600 && (a(this).attr("data-time", c), b.st() == 1 ? (b.circlBg(1), b._opt.onShow && b._opt.onShow()) : b.st() == 2 && (b.circlBg(0), b._opt.onHide && b._opt.onHide()))
                        }), c.taojiaIcons.click(function (c) {
                            var d = a(this),
                                e = d.attr("data-url"),
                                f = d.attr("name");
                            timer = setTimeout(function () {
                                b.circlHide2(), b._opt.onIconClick && b._opt.onIconClick(f), window.location.href = e
                            }, 500)
                        }), c.taojiaLogo.click(function (c) {
                            var d = a(this).attr("data-url");
                            timer = setTimeout(function () {
                                b.circlHide2(), TaoJia._opt.onLogoClick && TaoJia._opt.onLogoClick(), window.location.href = d
                            }, 500)
                        })
                    }
                };
            c.btn()
        },
        circlBg: function (b) {
            var c = this,
                d = {
                    taojiaDiv: a("#J_Taojia"),
                    taojiaTouch: a("#J_Taojia").find(".taoplus-btn"),
                    taojiaCircle: a("#J_Taojia").find(".taoplus-main"),
                    circlBg: a("#J_Taojia").find(".circlbg"),
                    circlLogo: a("#J_Taojia").find(".biglogo"),
                    taojiaLogo: a("#J_Taojia").find(".biglogo").find("a"),
                    taojiaIcons: a("#J_Taojia").find(".icons").find("a"),
                    taojiaIconBg: a("#J_Taojia").find(".backgrounds").find("li"),
                    timer: null,
                    num: 0,
                    taojiaIconShow: function () {
                        d.taojiaTouch.removeClass("hide").addClass("on")
                    },
                    taojiaIconHide: function () {
                        d.taojiaTouch.removeClass("on").addClass("hide")
                    },
                    circlShow: function () {
                        timer = setTimeout(d.circlAllShow, 0), timer = setTimeout(d.circlBgShow, 0), timer = setTimeout(d.circlIconShow, 100), timer = setTimeout(d.circlLogoShow, 200)
                    },
                    circlHide: function () {
                        timer = setTimeout(d.circlIconHide, 0), timer = setTimeout(d.circlLogoHide, 0), timer = setTimeout(d.circlBgHide, 300), timer = setTimeout(d.circlAllHide, 400)
                    },
                    circlAllShow: function () {
                        d.taojiaCircle.addClass("show")
                    },
                    circlAllHide: function () {
                        d.taojiaCircle.removeClass("show")
                    },
                    circlBgShow: function () {
                        d.circlBg.addClass("show")
                    },
                    circlBgHide: function () {
                        d.circlBg.removeClass("show")
                    },
                    circlLogoShow: function () {
                        d.circlLogo.addClass("show")
                    },
                    circlLogoHide: function () {
                        d.circlLogo.removeClass("show")
                    },
                    circlIconShow: function () {
                        var b = null,
                            c = 25,
                            b = setInterval(function () {
                                var c = a("#J_Taojia .icons").find(".show"),
                                    d = a("#J_Taojia .icons li"),
                                    e = a("#J_Taojia .icons").find("a"),
                                    f = a("#J_Taojia .backgrounds li"),
                                    g = c.size(),
                                    h = e.size();
                                g <= 0 ? (a(d[h - 1]).removeClass("hide").addClass("show"), a(f[h - 1]).removeClass("o").addClass("gray"), e.removeClass("on")) : g > 0 && g < h ? (a(d[h - g - 1]).removeClass("hide").addClass("show"), a(f[h - g - 1]).removeClass("o").addClass("gray"), a(f[h - g - 1]).siblings("li").removeClass("gray"), e.removeClass("on")) : g == h && (f.removeClass("gray"), clearInterval(b))
                            }, c)
                    },
                    circlIconHide: function () {
                        var b = 25;
                        timer = setInterval(function () {
                            var b = a("#J_Taojia .icons").find(".hide"),
                                c = a("#J_Taojia .icons li"),
                                d = a("#J_Taojia .icons").find("a"),
                                e = a("#J_Taojia .backgrounds li"),
                                f = b.size(),
                                g = d.size();
                            f <= 0 ? (a(c[0]).removeClass("show").addClass("hide"), a(e[0]).removeClass("o").addClass("gray")) : f > 0 && f < g ? (a(c[f]).removeClass("show").addClass("hide"), a(e[f]).removeClass("o").addClass("gray"), a(e[f]).siblings("li").removeClass("gray")) : f == g && (e.removeClass("gray"), clearInterval(timer))
                        }, b)
                    },
                    circlHide2: function () {
                        var a = null,
                            b = 20;
                        a = setTimeout(function () {
                            d.taojiaTouch.removeClass("hide").addClass("on"), d.taojiaCircle.find(".show").removeClass("show"), d.taojiaCircle.find(".o").removeClass("o"), d.taojiaCircle.removeClass("show")
                        }, b)
                    }
                };
            a(a("body > div")[0]).hasClass("ios") ? b == 1 ? (d.circlShow(), d.taojiaIconHide()) : b == 0 && (d.circlHide(), d.taojiaIconShow()) : b == 1 ? (d.circlAllShow(), d.taojiaIconHide()) : b == 0 && (d.circlAllHide(), d.taojiaIconShow())
        },
        st: function () {
            var b = {
                btn: a("#J_Taojia .taoplus-btn"),
                taojia: a("#J_Taojia"),
                st: function () {
                    if (b.taojia.attr("style") == "none") return 0;
                    if (b.btn.hasClass("on")) return 1;
                    if (b.btn.hasClass("hide")) return 2
                }
            };
            return b.st()
        },
        taojiaHide: function () {
            a("#J_Taojia").hide(), this.circlBg(0)
        },
        taojiaShow: function () {
            a("#J_Taojia").show()
        },
        circlHide: function () {
            this.circlBg(0)
        },
        circlHide2: function () {
            var b = a("#J_Taojia").find(".taoplus-btn"),
                c = a("#J_Taojia").find(".taoplus-main"),
                d = null,
                e = 20;
            d = setTimeout(function () {
                b.removeClass("hide").addClass("on"), c.find(".show").removeClass("show"), c.find(".o").removeClass("o"), c.removeClass("show")
            }, e)
        }
    }, TaoJia = H5.TaoPlus
}(Zepto),
function () {
    this.JST || (this.JST = {}), this.JST["templates/cart"] = function (obj) {
        var __p = [],
            print = function () {
                __p.push.apply(__p, arguments)
            };
        with(obj || {}) __p.push('  <div class="go-cart">\n    <a href="', url, '">已成功加入购物车,去购物车结算</a><span class="arrow right"></span>\n  </div>\n');
        return __p.join("")
    }
}.call(this),
function () {
    this.JST || (this.JST = {}), this.JST["templates/gallery"] = function (obj) {
        var __p = [],
            print = function () {
                __p.push.apply(__p, arguments)
            };
        with(obj || {}) {
            __p.push('<div class="wrap">\n  <div class="ctrls">\n    <a href="#" class="back-btn">返 回</a>\n    <a href="#" class="orig-btn">原 图</a>\n  </div>\n  <div class="slide">\n    <ul>\n    ');
            for (var i = 0; i < images.length; i++) __p.push('\n      <li><img class="lazy" data-original="', images[i], '" \n        src="http://a.tbcdn.cn/mw/base/styles/component/more/images/Loading_Taobao_320.gif"></li>\n    ');
            __p.push('\n    </ul>\n  </div>\n  <span class="arrow left" style="display: none;"></span>\n  <p class="page"><span class="active">1</span> / <span class="total">', images.length, '</span></p>\n  <span class="arrow right" style="', images.length > 1 ? "" : "display: none;", '"></span>\n</div>\n')
        }
        return __p.join("")
    }
}.call(this),
function () {
    this.JST || (this.JST = {}), this.JST["templates/notification"] = function (obj) {
        var __p = [],
            print = function () {
                __p.push.apply(__p, arguments)
            };
        with(obj || {}) __p.push('<p class="message">', message, "</p>\n"), action && __p.push('\n<div class="action">\n  <a href="#" class="now">立即整理</a><a href="#" class="later">稍后再说</a>\n</div>\n'), __p.push("\n");
        return __p.join("")
    }
}.call(this),
function () {
    this.JST || (this.JST = {}), this.JST["templates/pagination"] = function (obj) {
        var __p = [],
            print = function () {
                __p.push.apply(__p, arguments)
            };
        with(obj || {}) {
            __p.push('<ul>\n  <li class="prev ', index == 1 ? "disabled" : "", '">上一页</li>\n  <li>\n    <span class="active">', index, '</span>/<span class="total">', total, '</span>\n    <span class="arrow down"></span>\n    <select>\n      ');
            for (var i = 1; i <= total; i++) __p.push('\n        <option value="', i, '" ', i == index ? "selected" : "", ">第", i, "页</option>\n      ");
            __p.push('\n    </select>\n  </li>\n  <li class="next ', index == total ? "disabled" : "", '">下一页</li>\n</ul>\n')
        }
        return __p.join("")
    }
}.call(this),
function () {
    this.JST || (this.JST = {}), this.JST["templates/pop"] = function (obj) {
        var __p = [],
            print = function () {
                __p.push.apply(__p, arguments)
            };
        with(obj || {}) __p.push('<div class="pop">\n  <div class="main">\n    <span class="loading-orange30x12"></span>\n  </div\n</div>\n');
        return __p.join("")
    }
}.call(this),
function () {
    this.JST || (this.JST = {}), this.JST["templates/property"] = function (obj) {
        var __p = [],
            print = function () {
                __p.push.apply(__p, arguments)
            };
        with(obj || {}) __p.push(""), _.each(props, function (a) {
            __p.push('\n<div class="property">\n  <p class="name">', a.name, ':</p>\n  <div class="values">\n    '), _.each(a.values, function (b) {
                __p.push('\n      <a href="#" data-id="', b.id, '" data-img="', b.img || "", '" data-name="', a.name, '">\n        ', b.txt, "\n      </a>\n    ")
            }), __p.push("\n  </div>\n</div>\n")
        }), __p.push('\n<ul class="notice table">\n  <li class="left">\n    <p>请选:</p>\n    <p>', propNames, '</p>\n  </li>\n  <li class="chosen" style="display: none;">\n    <p>已选:</p>\n    <p></p>\n  </li>\n  <li class="sku-price" style="display: none;">\n    <p>价格:</p>\n    <p><em></em>   (库存 <span>68</span> 件)</p>\n  </li>\n</ul>\n<div class="fold"><a href="#" class="ctrl"><span class="arrow up"></span></a></div>\n');
        return __p.join("")
    }
}.call(this),
function () {
    this.JST || (this.JST = {}), this.JST["templates/recommend"] = function (obj) {
        var __p = [],
            print = function () {
                __p.push.apply(__p, arguments)
            };
        with(obj || {}) {
            __p.push('<header>\n  <h1>本店推荐产品</h1>\n</header>\n<div class="slide">\n  <ul>\n    ');
            for (var i = 0; i < Math.ceil(Math.min(items.length, 15) / 3); i++) {
                __p.push('\n      <li>\n        <div class="item-group">\n          ');
                for (var j = 0; j < 3; j++) __p.push("\n            "), items[i * 3 + j] && (__p.push('\n              <div class="item">\n                <a href="', items[i * 3 + j].link, '">\n                  <img class="lazy" data-original="', items[i * 3 + j].img, '" src="http://a.tbcdn.cn/mw/base/styles/component/more/images/Loading_Taobao_320.gif">\n                </a>\n                '), items[i * 3 + j].price && __p.push("\n                  <p>¥ ", items[i * 3 + j].price, "</p>\n                "), __p.push("\n              </div>\n            ")), __p.push("\n          ");
                __p.push("\n        </div>\n      </li>\n    ")
            }
            __p.push("\n  </ul>\n</div>\n\n");
            if (items.length > 3) {
                __p.push('\n<ul class="pager">\n  <li class="prev"><span class="arrow left"></span></li>\n  ');
                for (var i = 0; i < Math.ceil(Math.min(items.length, 15) / 3); i++) __p.push('\n    <li class="counter ', i == 0 ? "active" : "", '"></li>\n  ');
                __p.push('\n  <li class="next"><span class="arrow right"></span></li>\n</ul> \n')
            }
            __p.push("\n")
        }
        return __p.join("")
    }
}.call(this),
function () {
    this.JST || (this.JST = {}), this.JST["templates/review"] = function (obj) {
        var __p = [],
            print = function () {
                __p.push.apply(__p, arguments)
            };
        with(obj || {}) __p.push(""), reviews.length ? (__p.push("\n<ul>\n  "), _.each(reviews, function (a) {
            __p.push("\n  <li>\n    "), !tmall && !noReviewIcons && __p.push('\n      <span class="icon-review icon-review-', a.type, '"></span>\n    '), __p.push('\n    <div class="wrap">\n      <p class="text">', a.text, "</p>\n      "), a.reply && __p.push('\n        <p class="reply"><em>卖家回复:</em>', a.reply, "</p>\n      "), __p.push('\n      <p class="deal">', a.deal, '</p>\n      <p class="user">', a.user, '<span class="rank">', a.rank, "</span>", a.date, "</p>\n    </div>\n  </li>\n  ")
        }), __p.push("\n</ul>\n")) : __p.push('\n  <p class="notice">', message, "</p>\n"), __p.push("\n");
        return __p.join("")
    }
}.call(this),
function (a) {
    App.ActionView = Backbone.View.extend({
        events: {
            "click .btn-buy": "placeOrder",
            "click .btn-cart": "addToCart"
        },
        initialize: function () {
            var a = App.data;
            this.tmall = a.tmall, this.itemId = a.itemId, this.hasProps = a.hasProps, this.prevSkuId = a.prevSkuId, this.reAddCart = a.reAddCart, this.reAddFav = a.reAddFav, this.loginUrl = a.loginUrl.replace(/&/g, "&"), this.addCartUrl = a.addCartUrl.replace(/&/g, "&"), this.addFavUrl = a.addFavUrl.replace(/&/g, "&"), this.bindFavAction(), this.tmall && this.$(".btn-buy").addClass("btn-tmall")
        },
        addToCart: function (b) {
            b.preventDefault(), App.logUserAction("addcart#h#detail");
            var c = this;
            this.hasProps && !a("#sku-id").val() ? App.run("skuView:unfold") : a.ajax({
                url: this.addCartUrl,
                dataType: "jsonp",
                data: {
                    skuId: this.hasProps ? a("#sku-id").val() : ""
                },
                success: function (b) {
                    b = b || {};
                    if (b.status == "true") {
                        App.run("notificationView:notify", App.addCartSuccMsg), c._renderCartUrl();
                        return
                    }
                    if (b.errorCode == "NOT_LOGINED") {
                        window.location = c._appendRedirectUrl(c.loginUrl, "%26func=cart%26skuId=" + a("#sku-id").val());
                        return
                    }
                    if (b.total >= 50) {
                        App.run("notificationView:notify", App.cartIsFullMsg, !0);
                        return
                    }
                    App.run("notificationView:notify", b.error || App.errorMessage)
                },
                error: function () {
                    App.run("notificationView:notify", App.errorMessage)
                }
            })
        },
        bindFavAction: function () {
            var b = this;
            a(".fav.btn").on("click", function (c) {
                c.preventDefault(), App.logUserAction("addfav#h#detail"), a.ajax({
                    url: b.addFavUrl,
                    dataType: "jsonp",
                    success: function (c) {
                        c = c || {}, c.addFav ? (a(".fav.btn").addClass("faved"), App.run("notificationView:notify", App.addFavSuccMsg)) : c.msg.search("请登录后操作") > -1 ? window.location = b._appendRedirectUrl(b.loginUrl, "%26func=fav") : (App.run("notificationView:notify", c.msg || App.errorMessage), c.msg.search("您已经收藏过了") > -1 && a(".fav.btn").addClass("faved"))
                    },
                    error: function () {
                        App.run("notificationView:notify", App.errorMessage)
                    }
                })
            })
        },
        placeOrder: function (b) {
            b.preventDefault(), App.logUserAction("buynow#h#detail");
            if (this.hasProps && !a("#sku-id").val()) App.run("skuView:unfold");
            else {
                if (App.plugins && typeof App.plugins.buy == "function") {
                    App.plugins.buy();
                    return
                }
                a("#order-form").submit()
            }
        },
        performPreviousAction: function (b) {
            if (!(window.localStorage && localStorage.getItem && localStorage.setItem)) return;
            var c = localStorage.getItem("[detail]funcStates"),
                d = c ? JSON.parse(c) : {
                    id: this.itemId,
                    hasAddedCart: !1,
                    hasAddedFav: !1
                };
            if (d.id == this.itemId) {
                if (d.hasAddedCart && this.reAddCart || d.hasAddedFav && this.reAddFav) return
            } else d.id = this.itemId, d.hasAddedCart = !1, d.hasAddedFav = !1, localStorage.setItem("[detail]funcStates", JSON.stringify(d));
            if (!this.reAddCart && !this.reAddFav) return;
            if (this.hasProps && b) {
                for (var e in b) if (this.prevSkuId == b[e].skuId) {
                    App.run("skuView:restore", e.split(";"));
                    break
                }
                App.run("skuView:unfold")
            }
            this.reAddCart && this.$(".btn-cart").trigger("click") && (d.hasAddedCart = !0), this.reAddFav && a(".fav.btn").trigger("click") && (d.hasAddedFav = !0), localStorage.setItem("[detail]funcStates", JSON.stringify(d))
        },
        _appendRedirectUrl: function (a, b) {
            var c = a.split("&");
            for (var d = 0; d < c.length; d++) if (c[d].search("tpl_redirect_url") > -1) {
                c[d] = c[d] + b;
                break
            }
            return c.join("&")
        },
        _renderCartUrl: function () {
            if (a(".go-cart").length) return;
            return this.$el.after(JST["templates/cart"]({
                url: App.data.myCartUrl
            })), this
        }
    })
}(Zepto),
function (a) {
    App.DescriptionView = Backbone.View.extend({
        events: {
            "click  .pagination .prev": "prevPage",
            "click  .pagination .next": "nextPage",
            "change .pagination select": "changePage"
        },
        initialize: function () {
            this.url = App.data.descAjaxUrl, this.data = {
                index: 1,
                total: 0,
                pages: [undefined]
            }, this.firstRender = !0
        },
        getData: function () {
            var b = this;
            a.ajax({
                url: this.url,
                dataType: "json",
                success: function (a) {
                    b.data.pages = [undefined].concat(b._convert(a && a.pages || [])), b.data.total = a && a.pages && a.pages.length || 0, b.render()
                },
                error: function () {}
            })
        },
        render: function () {
            return this.firstRender ? this.firstRender = !1 : App.tabsFocus(), this.data.index == 1 ? this.$(".table").show() : this.$(".table").hide(), this.$(".main").html(this.data.pages[this.data.index]), this.data.total > 0 && this.paginate(), this
        },
        paginate: function () {
            this.$(".pagination").html(JST["templates/pagination"]({
                index: this.data.index,
                total: this.data.total
            }))
        },
        toPage: function (a) {
            this.data.index = a, this.render()
        },
        changePage: function (b) {
            this.toPage(parseInt(a(b.target).val()))
        },
        prevPage: function () {
            if (this.data.index == 1) return;
            this.toPage(--this.data.index), App.logUserAction("auuppage#h#detail")
        },
        nextPage: function () {
            if (this.data.index == this.data.total) return;
            this.toPage(++this.data.index), App.logUserAction("aunextpage#h#detail")
        },
        _convert: function (a) {
            var b = [];
            for (var c = 0; c < a.length; c++) {
                var d = a[c].replace(/<img[^>]+taobao[^>]+jpg[^>]*>/ig, function (a) {
                    if (a.search(/\d+x\d+\.jpg/) > -1 || a.match(/jpg/g).length > 1) return a;
                    var b = a.indexOf("jpg"),
                        c = App.data.imgScale == 2 ? "_400x400.jpg" : "_310x310.jpg";
                    return a.slice(0, b + 3) + c + a.slice(b + 3)
                });
                b.push(d)
            }
            return b
        }
    })
}(Zepto),
function (a) {
    App.GalleryView = Backbone.View.extend({
        template: JST["templates/gallery"],
        events: {
            "click .slide img": "fullScreen",
            "click .back-btn": "restore",
            "click .orig-btn": "showOrig"
        },
        initialize: function () {
            App.data.images && App.data.images.length > 0 ? this.images = App.convertImages(App.data.images, App.data.imgScale == 2 ? "460x460" : "310x310") : this.images = [App.defaultImage]
        },
        render: function () {
            var a = this.template({
                images: this.images
            });
            return this.$el.html(a), this
        },
        setup: function () {
            var a = this;
            return this.$(".arrow.left").hide(), this.slide = new Swipe(this.$(".slide")[0], {
                preload: !0,
                callback: function (b, c) {
                    a.$(".page .active").text(c + 1), a.$(".arrow").show(), c == 0 && a.$(".arrow.left").hide(), c == this.length - 1 && a.$(".arrow.right").hide(), a.slide.swipe ? a.slide.prevIndex > c ? App.logUserAction("muppic#h#detail") : App.logUserAction("mnextpic#h#detail") : a.slide.prevIndex > c ? App.logUserAction("uppic#h#detail") : App.logUserAction("nextpic#h#detail"), a.slide.swipe = !0, a.slide.prevIndex = c
                }
            }), this.slide.swipe = !0, this.slide.prevIndex = 0, this.slide.load(), this.$(".arrow.left").on("click", function () {
                a.slide.prev(), a.slide.swipe = !1
            }), this.$(".arrow.right").on("click", function () {
                a.slide.next(), a.slide.swipe = !1
            }), this
        },
        fullScreen: function () {
            if (this.$el.hasClass("float")) return;
            App.data.taoPlus && (a("#J_Taojia").hide(), a(".h5 > header").hide()), a("content").hide(), this.$el.addClass("float"), this.$el.prependTo(".detail"), this.slide.setup(), App.logUserAction("getpic#h#detail")
        },
        restore: function () {
            App.data.taoPlus && (a("#J_Taojia").show(), a(".h5 > header").show()), this.$el.removeClass("float"), this.$el.prependTo(".appearance"), this.slide.setup(), a(".content").show()
        },
        showOrig: function () {
            App.logUserAction("originalpic#h#detail"), window.location = App.data.images[this.slide.index]
        }
    })
}(Zepto),
function (a) {
    App.NotificationView = Backbone.View.extend({
        className: "notification",
        events: {
            "click .now": "goToCart",
            "click .later": "later"
        },
        template: JST["templates/notification"],
        initialize: function () {
            this.myCartUrl = App.data.myCartUrl, this.cleanNowUrl = App.data.cleannowUrl
        },
        render: function () {
            return this.$el.html(this.template({
                message: "",
                action: !0
            })), a(".detail").prepend(this.el), this.$el.hide().css("z-index", "999"), this
        },
        notify: function (a, b) {
            var c = this;
            return this.$(".message").text(a), b ? this.$(".action").show() : (this.$(".action").hide(), setTimeout(function () {
                c.hide()
            }, 2e3)), this.show(), this
        },
        goToCart: function () {
            this.$el.hide(), window.location = this.myCartUrl
        },
        later: function () {
            this.hide(), App.logUserAction("clearnlater#h#cart")
        },
        show: function () {
            this.$el.show(), this.$el.animate({
                top: 0
            }, 200)
        },
        hide: function () {
            this.$el.animate({
                top: -90
            }, 200);
            var a = this;
            setTimeout(function () {
                a.$el.hide()
            }, 200)
        }
    })
}(Zepto),
function (a) {
    App.RecommendView = Backbone.View.extend({
        template: JST["templates/recommend"],
        initialize: function () {
            this.url = App.data.recommendAjaxUrl, this.tmall = App.data.tmall, this.items = []
        },
        render: function () {
            var a = this;
            if (this.items.length == 0) {
                this.$el.remove();
                return
            }
            return this.convertImages(), this.$el.html(this.template({
                items: this.items
            })), this.tmall && this.$(".pager").addClass("tmall"), this.slide = new Swipe(this.$(".slide")[0], {
                preload: !0,
                callback: function () {
                    a.$(".counter").removeClass("active").eq(a.slide.index).addClass("active")
                }
            }), this.slide.load(), this.$(".prev").bind("click", function () {
                a.slide.prev()
            }), this.$(".next").bind("click", function () {
                a.slide.index < a.slide.length - 1 && a.slide.next()
            }), this
        },
        listen: function () {
            function c(d) {
                d.preventDefault(), b.$el.offset().top < window.pageYOffset + window.innerHeight + 500 && (b.getData(), a(window).off("scroll", c))
            }
            var b = this;
            a(window).on("scroll", c)
        },
        getData: function () {
            var b = this;
            a.ajax({
                url: this.url,
                dataType: "json",
                success: function (a) {
                    a && a.items && a.items.length && (b.items = a.items), b.hasPrice = a && a.hasPrice, b.render()
                },
                error: function () {
                    b.$el.remove()
                }
            })
        },
        convertImages: function () {
            var a;
            for (var b = 0; b < this.items.length; b++) a = this.items[b], a.img = App.convertImages(a.img, App.data.imgScale == 2 ? "145x145" : "110x110")
        }
    })
}(Zepto),
function (a) {
    App.ReviewView = Backbone.View.extend({
        typeMap: {
            all: "",
            good: "1",
            ok: "0",
            bad: "-1",
            1: "good",
            0: "ok",
            "-1": "bad"
        },
        messages: {
            all: "该宝贝没有任何评论",
            good: "该宝贝没有好评",
            ok: "该宝贝没有中评",
            bad: "该宝贝没有差评"
        },
        events: {
            "click  .types li": "toType",
            "click  .fold .ctrl": "toggle",
            "click  .pagination .prev": "prevPage",
            "click  .pagination .next": "nextPage",
            "change .pagination select": "changePage"
        },
        template: JST["templates/review"],
        initialize: function () {
            this.url = App.data.reviewAjaxUrl, this.tmall = App.data.tmall, this.noReviewIcons = App.data.noReviewIcons, this.folded = !0, this.type = "all", this.data = {
                all: {
                    index: 1,
                    total: 0,
                    pages: [undefined]
                },
                good: {
                    index: 1,
                    total: 0,
                    pages: [undefined]
                },
                ok: {
                    index: 1,
                    total: 0,
                    pages: [undefined]
                },
                bad: {
                    index: 1,
                    total: 0,
                    pages: [undefined]
                }
            }, this.$(".types").hide(), this.tmall && this.$(".types").remove(), this.firstRender = !0, this.firstFold = !0
        },
        render: function (a, b) {
            this.firstRender ? this.firstRender = !1 : App.tabsFocus(), this.type == "all" && this.getTotal() == 0 && (this.$(".types").remove(), this.$(".fold").remove());
            var c = this.data[a].pages[b],
                d = this.template({
                    type: a,
                    tmall: this.tmall,
                    reviews: c,
                    noReviewIcons: this.noReviewIcons,
                    message: this.messages[a]
                });
            return this.$(".main").html(d), this.paginate(), this.changeTypeTab(), this.folded && this.fold(), this
        },
        getData: function (b, c) {
            var d = this;
            this.xhr && this.xhr.abort(), this.xhr = a.ajax({
                url: this.url,
                data: {
                    rateRs: this.typeMap[b],
                    p: c,
                    ps: 10
                },
                dataType: "json",
                success: function (a) {
                    d.type = b, d.data[b].index = c, d.data[b].total = a && a.total || 0, d.data[b].pages[c] = a && d._convert(a.items || []), d.render(b, c)
                },
                error: function () {}
            })
        },
        paginate: function () {
            if (this.getTotal() == 0) return;
            this.$(".pagination").html(JST["templates/pagination"]({
                index: this.getIndex(),
                total: this.getTotal()
            }))
        },
        changeTypeTab: function () {
            var b = this.type;
            this.$(".types li").removeClass("active").each(function () {
                var c = a(this);
                c.attr("data-tab") == b && c.addClass("active")
            })
        },
        getIndex: function () {
            return this.data[this.type].index
        },
        getTotal: function () {
            return this.data[this.type].total
        },
        toType: function (b) {
            var c = a(b.target).attr("data-tab"),
                d = this.data[c].index;
            this.data[c].pages[d] == null ? this.getData(c, d) : (this.type = c, this.render(c, d)), c == "all" ? App.logUserAction("sayall#h#detail") : c == "good" ? App.logUserAction("saygood#h#detail") : c == "ok" ? App.logUserAction("saynormal#h#detail") : c == "bad" && App.logUserAction("saybad#h#detail")
        },
        toPage: function (a) {
            this.data[this.type].pages[a] == null ? this.getData(this.type, a) : (this.data[this.type].index = a, this.render(this.type, a))
        },
        prevPage: function () {
            var a = this.data[this.type].index;
            if (a == 1) return;
            this.toPage(--a), App.logUserAction("reuppage#h#detail")
        },
        nextPage: function () {
            var a = this.data[this.type].index,
                b = this.data[this.type].total;
            if (a == b) return;
            this.toPage(++a), App.logUserAction("renextpage#h#detail")
        },
        changePage: function (b) {
            this.toPage(a(b.target).val())
        },
        fold: function (b) {
            this.$(".types").hide(), this.$(".pagination").hide(), this.$(".fold .arrow").removeClass("up").addClass("down"), this.$(".main li").each(function (b) {
                b > 2 && a(this).hide()
            }), this.firstFold ? this.firstFold = !1 : App.tabsFocus(), b && App.logUserAction("hidecomment#h#detail")
        },
        unfold: function (a) {
            this.$(".types").show(), this.$(".main li").show(), this.$(".pagination").show(), this.$(".fold .arrow").removeClass("down").addClass("up"), a && App.logUserAction("morecomment#h#detail")
        },
        toggle: function (a) {
            a.preventDefault(), this.folded ? (this.unfold(a), this.folded = !1) : (this.fold(a), this.folded = !0)
        },
        _convert: function (b) {
            function c(a) {
                var b = H5.creditToRank(a),
                    c = ["", "颗心", "颗黄钻", "金冠", "紫冠"],
                    d = Math.ceil(b / 5),
                    e = (b - 5 * (d - 1)) % 6;
                return b ? e + " " + c[d] : ""
            }
            var d = this,
                e = [];
            return a.each(b, function (a, b) {
                e.push({
                    type: d.typeMap[b.type],
                    text: b.text,
                    date: b.date,
                    deal: b.deal,
                    reply: b.reply,
                    user: b.buyer,
                    rank: c(b.credit)
                })
            }), e
        }
    })
}(Zepto),
function (a) {
    App.data.coins = a(".price .coins").text(), App.data.promoPrice = a(".price .promo-price").text(), App.SkuView = Backbone.View.extend({
        template: JST["templates/property"],
        events: {
            "click .ctrl": "fold",
            "click .props": "unfold",
            "click .values a": "select"
        },
        initialize: function () {
            this.url = App.data.propsAjaxUrl, App.data.tmall && this.$el.addClass("tmall")
        },
        render: function () {
            this.propNames = _.pluck(this.skuProps, "name"), this.formatedPropNames = this.format(this.propNames);
            var a = this.template({
                props: this.skuProps,
                propNames: this.formatedPropNames
            }).replace(/\s*\n\s*/g, "");
            return this.$(".main").html(a), this.adjust(), this.fold(), this
        },
        format: function (a) {
            return _(a).map(function (a) {
                return " “<em>" + a + "</em>” "
            }).join(" ")
        },
        getData: function () {
            var b = this;
            a.ajax({
                url: b.url,
                dataType: "json",
                success: function (a) {
                    b.skuProps = a && a.skuProps || [], b.availSKUs = a && a.availSKUs || {}, b.render(), App.run("actionView:performPreviousAction", b.availSKUs)
                },
                error: function () {
                    alert(App.errorMessage)
                }
            })
        },
        select: function (b) {
            b.preventDefault(), $val = a(b.target);
            if ($val.hasClass("disabled")) return;
            a("#sku-id").val(""), $val.attr("data-img") && !$val.hasClass("selected") ? this.popImage($val) : $val.parent().find(".pop").remove(), $val.hasClass("selected") ? $val.removeClass("selected") : ($val.addClass("selected"), $val.siblings().removeClass("selected")), this.notice(), this.disable(), this.setPrice()
        },
        notice: function () {
            a(".price .promo-price").length && this.$(".sku-price p:first-child").text("促销:");
            var b = this.$(".selected"),
                c = [],
                d = [];
            b.each(function (b, e) {
                c.push(a(e).attr("data-name")), d.push(a(e).text())
            });
            var e = _.difference(this.propNames, c);
            b.length == 0 ? (this.$(".notice .left").show(), this.$(".notice .left p:last-child").html(this.formatedPropNames), this.$(".notice .chosen").css("display", "none"), this.$(".notice .sku-price").css("display", "none")) : b.length == this.skuProps.length ? (this.$(".notice .left").css("display", "none"), this.$(".notice .chosen p:last-child").html(this.format(d)), this.$(".notice .chosen").show(), this.$(".notice .sku-price").show()) : (this.$(".notice .left").show(), this.$(".notice .left p:last-child").html(this.format(e)), this.$(".notice .chosen").show(), this.$(".notice .chosen p:last-child").html(this.format(d)), this.$(".sku-price").css("display", "none"))
        },
        disable: function () {
            var b = this;
            this.$values.removeClass("disabled");
            var c = this.$(".selected");
            if (c.length == 0) return;
            if (this.$(".property").length == 1) return;
            this.$values.each(function () {
                var c = a(this);
                if (c.hasClass("selected")) {
                    var d = c.parent().parent().siblings().find("a");
                    d.each(function (a, e) {
                        var f = !1;
                        for (var g in b.availSKUs) if (g.search(c.attr("data-id")) > -1 && g.search(d.eq(a).attr("data-id")) > -1) {
                            f = !0;
                            break
                        }
                        f || d.eq(a).addClass("disabled")
                    })
                }
            })
        },
        setPrice: function () {
            var b = this.$(".selected");
            if (b.length == this.skuProps.length) {
                var c = [];
                b.each(function (b, d) {
                    c.push(a(d).attr("data-id"))
                });
                var d = c.join(";");
                for (var e in this.availSKUs) if (d === e) {
                    var f = this.availSKUs[e];
                    a("#sku-id").val(f.skuId), this.$(".sku-price span").text(f.quantity), this.$(".sku-price em").text("¥" + (f.promoPrice || f.price) + (App.data.coins || "")), a(".price li:first-child p:last-child").text("¥" + f.price), a(".price .promo-price").text("¥" + f.promoPrice + (App.data.coins || ""));
                    break
                }
            } else a(".price li:first-child p:last-child").text(App.data.price), a(".price .promo-price").text(App.data.promoPrice)
        },
        adjust: function () {
            this.$values = this.$(".values a"), this.$values.each(function () {
                var b = a(this),
                    c = b.width();
                c < 32 ? b.addClass("a") : c < 80 ? b.addClass("b") : c < 138 ? b.addClass("c") : b.addClass("d")
            }), this.$(".property").each(function () {
                var b = a(this),
                    c = 0;
                a("a", b).each(function () {
                    var b = a(this),
                        d = 1;
                    b.hasClass("a") ? d = 1 : b.hasClass("b") ? d = 2 : d = 3;
                    if (c + d < 6 && b.next().length) {
                        c += d;
                        return
                    }
                    if (c + d < 6 && b.next().length == 0 || c + d == 6) {
                        b.addClass("last"), c = 0;
                        return
                    }
                    c + d > 6 && (b.prev().addClass("last"), c = d, b.next().length == 0 && b.addClass("last"))
                })
            })
        },
        popImage: function (a) {
            var b = this,
                c = function (a) {
                    return a.hasClass("last") ? a : arguments.callee(a.next())
                }, d = function (a) {
                    var a = a.search(/jpg$/) > -1 ? a + "_210x210.jpg" : a,
                        c = new Image;
                    c.onload = function () {
                        b.$(".pop span").hide(), b.$(".pop .main").append('<img src="' + a + '" style="opacity: 0;" />'), b.$(".pop img").animate({
                            opacity: 1
                        }, App.fideInTime)
                    }, c.src = a
                }, e = c(a);
            e.next().hasClass("pop") ? (this.$(".pop img").remove(), this.$(".pop span").show()) : (this.$(".pop").remove(), e.after(JST["templates/pop"]())), d(a.attr("data-img"))
        },
        restore: function (b) {
            for (var c = 0; c < b.length; c++) this.$(".values a").each(function () {
                a(this).attr("data-id") == b[c] && a(this).trigger("click")
            })
        },
        fold: function (a) {
            return this.$(".main").hide(), this.$(".props").show(), a && App.logUserAction("hidefeature#h#detail"), !1
        },
        unfold: function (a) {
            return this.$(".main").show(), this.$(".props").hide(), a && App.logUserAction("feature#h#detail"), !1
        }
    })
}(Zepto),
function (a) {
    App.Router = Backbone.Router.extend({
        routes: {
            "": "index",
            gallery: "gallery"
        },
        initialize: function () {
            App.galleryView = new App.GalleryView({
                el: ".gallery"
            }), App.galleryView.render().setup(), App.data.hasProps ? App.skuView = new App.SkuView({
                el: ".sku"
            }) : a(".sku").remove(), App.skuView && App.skuView.getData(), App.notificationView = new App.NotificationView, App.notificationView.render(), App.actionView = new App.ActionView({
                el: ".sales .action"
            }), (!App.data.hasProps && App.data.reAddCart || App.data.reAddFav) && App.actionView.performPreviousAction(), this.setupTabs(), this.adjustTableStyle(), App.reviewView = new App.ReviewView({
                el: ".review"
            }), App.reviewView.toPage(1), App.descriptionView = new App.DescriptionView({
                el: ".description"
            }), App.descriptionView.getData(), App.recommendView = new App.RecommendView({
                el: ".recommend"
            }), App.recommendView.listen(), App.data.taoPlus && this.initTaoPlus()
        },
        index: function () {
            App.galleryView.restore()
        },
        gallery: function () {
            App.galleryView.fullScreen()
        },
        setupTabs: function () {
            App.data.tmall && a(".tab-list").addClass("tmall"), a("#tabs li").each(function (b) {
                a(this).attr("data-tab", b).on("click", function () {
                    a("#tabs li").removeClass("active");
                    var b = a(this).addClass("active");
                    b.attr("data-tab") == 0 ? a(".review").show() : a(".review").hide(), b.attr("data-tab") == 1 ? a(".description").show() : a(".description").hide(), b.attr("data-tab") == 0 && App.logUserAction("comment#h#detail"), b.attr("data-tab") == 1 && App.logUserAction("getinfo#h#detail")
                })
            }), a(".review-count").on("click", function () {
                App.logUserAction("getcomment#h#detail"), a("#tabs li").removeClass("active").eq(0).addClass("active"), a(".review").show(), a(".description").hide()
            })
        },
        adjustTableStyle: function () {
            a(".description").show();
            var b = 62;
            a(".description .table .label").each(function () {
                var c = a(this);
                c.width() > b && (b = c.width())
            }), a(".description .table .label").width(b + 14 + "px"), a(".description").hide()
        },
        initTaoPlus: function () {
            a("header").attr("id", "header"), a(".h5").attr("id", "tbh5v0");
            var b = new a.swipeTop({
                wrap: "tbh5v0",
                toptabHeight: 0,
                headerHeight: 50
            });
            b.setOp("taojia", H5.TaoPlus), H5.TaoPlus.initialize({
                onShow: function () {
                    b.tapDown()
                },
                onHide: function () {
                    b.tapDown()
                }
            })
        },
        start: function () {
            Backbone.history.start()
        }
    }), a(function () {
        (new App.Router).start()
    })
}(Zepto);


仔细阅读了下,大致了解了脉络。搜索:reviewAjaxUrl,搜索到的函数体内有如下内嵌函数:

getData: function (b, c) {
            var d = this;
            this.xhr && this.xhr.abort(), this.xhr = a.ajax({
                url: this.url,
                data: {
                    rateRs: this.typeMap[b],
                    p: c,
                    ps: 10
                },
                dataType: "json",
                success: function (a) {
                    d.type = b, d.data[b].index = c, d.data[b].total = a && a.total || 0, d.data[b].pages[c] = a && d._convert(a.items || []), d.render(b, c)
                },
                error: function () {}
            })
        },

这里的data中的3个参数rateRs, p, ps即为要查找的参数。

加上参数试试吧:http://a.m.tmall.com/ajax/rate_list.do?item_id=xxxx&p=2&ps=15

获取的内容如下(JSON格式):

{"index":2,"items":[{"annoy":0,"buyer":"xxx","credit":91,"date":"2012-07-17","deal":"","rateId":19890633089,"text":"发货超快,经济实惠,以后就买你家产品了","type":0},{"annoy":0,"buyer":"xxx","credit":91,"date":"2012-07-16","deal":"","rateId":19859269704,"reply":"感谢您对我们的肯定和支持,非常感谢您对我们的服务认可,衷心的希望您能常来我们店!!!!o(∩_∩)o","text":"不好意思啊,确认晚了,发货速度很快,客服的态度也很好,特别是小依,有什么问题总能很快的得到答复.这已经是第三次购买了.","type":0},{"annoy":0,"buyer":"xxx","credit":501,"date":"2012-07-14","deal":"","rateId":19823225928,"reply":"亲,十一坊的纯的乳清蛋白粉溶解度是很好的,如果您说的其它品牌溶解速度快,那是因为那款产品里面加了速溶剂,而速溶剂属于添加剂呀,所以希望你能理解这点。另外十一坊纯乳清蛋白粉的原料是新西兰原产地纯牛奶提炼的,不知道怎么亲会闻出来羊奶味,我们有相关资质可以作证的,希望亲在好好闻闻哈!","text":"蛋白粉是我用过的的,外观最细腻的,泡沫最多的一款蛋白粉,同样也是奶味最浓的一款蛋白粉,有很浓的羊奶膻味,,(注意不是牛奶,不知为什么,)但是和美国大品牌蛋白粉比起来溶解度差,美国大品牌都是见水吉化,这款差点","type":0},{"annoy":0,"buyer":"xxx","credit":11,"date":"2012-07-14","deal":"","rateId":19816990927,"text":"好","type":0},{"annoy":0,"buyer":"xxx","credit":91,"date":"2012-07-13","deal":"","rateId":19801085374,"reply":"亲,多多关注我们店铺哦,还有更多优惠进行中~~~","text":"第二次购买了,不错的卖家。以后还会回来买。","type":0},{"annoy":0,"buyer":"xxx09","credit":11,"date":"2012-07-12","deal":"","rateId":19756966488,"reply":"感谢您对我们的肯定和支持,衷心的希望您能常来我们店!","text":"很好,有赠品和挂奖卡带金卡","type":0},{"annoy":0,"buyer":"xxx","credit":91,"date":"2012-07-11","deal":"","rateId":19726634975,"reply":"非常感谢您对店的支持~~~","text":"hao dong xi","type":0},{"annoy":0,"buyer":"xxx","credit":251,"date":"2012-07-09","deal":"","rateId":19678002719,"reply":"感谢您对我们的肯定和支持,衷心的希望您能常来我们店!","text":"很好,超划算,下次再来,谢谢小礼物","type":0},{"annoy":0,"buyer":"xxx","credit":251,"date":"2012-07-09","deal":"","rateId":19675522722,"text":"第一次来,卖家服务真好,还送了礼物,哈,还中了三等奖,别然小礼品一份,但也可看出卖家的用心,好评,会常来。","type":0},{"annoy":1,"buyer":"a**0","credit":41,"date":"2012-07-09","deal":"","rateId":19673848752,"text":"妈妈吃了,感觉还可以。坚持吃看看效果了哇。谢谢卖家的晓礼物哦","type":0},{"annoy":0,"buyer":"xxx","credit":41,"date":"2012-07-09","deal":"","rateId":19670631439,"reply":"亲,多多关注我们店铺哦,还有更多优惠进行中~~~","text":"一如即往的好,老顾客了","type":0},{"annoy":0,"buyer":"xxxx","credit":282,"date":"2012-07-06","deal":"","rateId":19611318847,"reply":"亲们若有疑问请拨打十一坊免费营养咨询热线:800 888 9988 ,非常感谢您对店的支持,祝您天天好心情~~","text":"发货速度很快,物流也很好。虽没查证,但感觉是正品,买家服务态度也很好,落发了一个摇摇杯说要给我寄过来,正在吃希望有效果,有效果再来喽!全5分好评了。。。。。","type":0},{"annoy":1,"buyer":"3**王","credit":4,"date":"2012-07-06","deal":"","rateId":19607636363,"text":"可以","type":0},{"annoy":0,"buyer":"xxx","credit":152,"date":"2012-07-06","deal":"","rateId":19596872786,"text":"蛋白粉一直在吃非常好","type":0},{"annoy":0,"buyer":"xxx","credit":152,"date":"2012-07-03","deal":"","rateId":19522938766,"text":"谢谢送的小赠品,还没喝不过看上去还不错","type":0}],"total":9}

经过几次更改参数,得出如下结论:

p表示page;

ps表示page size;

结果中的total为总页数(随ps的不同而不同).

rateRs应该为评价结果,取值如下:all, good, ok, bad, 1, 0, -1. 但是加上这个参数没有起作用,不知什么原因。

至此,可以完整的实现一个商品评价数据的抓取了,可以分页抓取。


注:为避免商家及买家用户信息泄露,对敏感处以xxx取代。本文仅供技术研究,不得用于其他非正常或非法用途,“Don't be evil". 转载请注明出处(http://blog.csdn.net/wave_1102/article/details/7829911)。


你可能感兴趣的:(c,function,object,null,delete,Class)