var GIGO = {};

(function(e, t) {
    var n, r, i = typeof t, o = e.location, a = e.document, s = a.documentElement, l = e.jQuery, u = e.$, c = {}, p = [], f = "1.10.2", d = p.concat, h = p.push, g = p.slice, m = p.indexOf, y = c.toString, v = c.hasOwnProperty, b = f.trim, x = function(e, t) {
        return new x.fn.init(e, t, r);
    }, w = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, T = /\S+/g, C = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, N = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, k = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, E = /^[\],:{}\s]*$/, S = /(?:^|:|,)(?:\s*\[)+/g, A = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, j = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, D = /^-ms-/, L = /-([\da-z])/gi, H = function(e, t) {
        return t.toUpperCase();
    }, q = function(e) {
        (a.addEventListener || "load" === e.type || "complete" === a.readyState) && (_(), 
        x.ready());
    }, _ = function() {
        a.addEventListener ? (a.removeEventListener("DOMContentLoaded", q, !1), e.removeEventListener("load", q, !1)) : (a.detachEvent("onreadystatechange", q), 
        e.detachEvent("onload", q));
    };
    x.fn = x.prototype = {
        jquery: f,
        constructor: x,
        init: function(e, n, r) {
            var i, o;
            if (!e) return this;
            if ("string" == typeof e) {
                if (i = "<" === e.charAt(0) && ">" === e.charAt(e.length - 1) && e.length >= 3 ? [ null, e, null ] : N.exec(e), 
                !i || !i[1] && n) return !n || n.jquery ? (n || r).find(e) : this.constructor(n).find(e);
                if (i[1]) {
                    if (n = n instanceof x ? n[0] : n, x.merge(this, x.parseHTML(i[1], n && n.nodeType ? n.ownerDocument || n : a, !0)), 
                    k.test(i[1]) && x.isPlainObject(n)) for (i in n) x.isFunction(this[i]) ? this[i](n[i]) : this.attr(i, n[i]);
                    return this;
                }
                if (o = a.getElementById(i[2]), o && o.parentNode) {
                    if (o.id !== i[2]) return r.find(e);
                    this.length = 1, this[0] = o;
                }
                return this.context = a, this.selector = e, this;
            }
            return e.nodeType ? (this.context = this[0] = e, this.length = 1, this) : x.isFunction(e) ? r.ready(e) : (e.selector !== t && (this.selector = e.selector, 
            this.context = e.context), x.makeArray(e, this));
        },
        selector: "",
        length: 0,
        toArray: function() {
            return g.call(this);
        },
        get: function(e) {
            return null == e ? this.toArray() : 0 > e ? this[this.length + e] : this[e];
        },
        pushStack: function(e) {
            var t = x.merge(this.constructor(), e);
            return t.prevObject = this, t.context = this.context, t;
        },
        each: function(e, t) {
            return x.each(this, e, t);
        },
        ready: function(e) {
            return x.ready.promise().done(e), this;
        },
        slice: function() {
            return this.pushStack(g.apply(this, arguments));
        },
        first: function() {
            return this.eq(0);
        },
        last: function() {
            return this.eq(-1);
        },
        eq: function(e) {
            var t = this.length, n = +e + (0 > e ? t : 0);
            return this.pushStack(n >= 0 && t > n ? [ this[n] ] : []);
        },
        map: function(e) {
            return this.pushStack(x.map(this, function(t, n) {
                return e.call(t, n, t);
            }));
        },
        end: function() {
            return this.prevObject || this.constructor(null);
        },
        push: h,
        sort: [].sort,
        splice: [].splice
    }, x.fn.init.prototype = x.fn, x.extend = x.fn.extend = function() {
        var e, n, r, i, o, a, s = arguments[0] || {}, l = 1, u = arguments.length, c = !1;
        for ("boolean" == typeof s && (c = s, s = arguments[1] || {}, l = 2), "object" == typeof s || x.isFunction(s) || (s = {}), 
        u === l && (s = this, --l); u > l; l++) if (null != (o = arguments[l])) for (i in o) e = s[i], 
        r = o[i], s !== r && (c && r && (x.isPlainObject(r) || (n = x.isArray(r))) ? (n ? (n = !1, 
        a = e && x.isArray(e) ? e : []) : a = e && x.isPlainObject(e) ? e : {}, s[i] = x.extend(c, a, r)) : r !== t && (s[i] = r));
        return s;
    }, x.extend({
        expando: "jQuery" + (f + Math.random()).replace(/\D/g, ""),
        noConflict: function(t) {
            return e.$ === x && (e.$ = u), t && e.jQuery === x && (e.jQuery = l), x;
        },
        isReady: !1,
        readyWait: 1,
        holdReady: function(e) {
            e ? x.readyWait++ : x.ready(!0);
        },
        ready: function(e) {
            if (e === !0 ? !--x.readyWait : !x.isReady) {
                if (!a.body) return setTimeout(x.ready);
                x.isReady = !0, e !== !0 && --x.readyWait > 0 || (n.resolveWith(a, [ x ]), x.fn.trigger && x(a).trigger("ready").off("ready"));
            }
        },
        isFunction: function(e) {
            return "function" === x.type(e);
        },
        isArray: Array.isArray || function(e) {
            return "array" === x.type(e);
        },
        isWindow: function(e) {
            return null != e && e == e.window;
        },
        isNumeric: function(e) {
            return !isNaN(parseFloat(e)) && isFinite(e);
        },
        type: function(e) {
            return null == e ? e + "" : "object" == typeof e || "function" == typeof e ? c[y.call(e)] || "object" : typeof e;
        },
        isPlainObject: function(e) {
            var n;
            if (!e || "object" !== x.type(e) || e.nodeType || x.isWindow(e)) return !1;
            try {
                if (e.constructor && !v.call(e, "constructor") && !v.call(e.constructor.prototype, "isPrototypeOf")) return !1;
            } catch (r) {
                return !1;
            }
            if (x.support.ownLast) for (n in e) return v.call(e, n);
            for (n in e) ;
            return n === t || v.call(e, n);
        },
        isEmptyObject: function(e) {
            var t;
            for (t in e) return !1;
            return !0;
        },
        error: function(e) {
            throw Error(e);
        },
        parseHTML: function(e, t, n) {
            if (!e || "string" != typeof e) return null;
            "boolean" == typeof t && (n = t, t = !1), t = t || a;
            var r = k.exec(e), i = !n && [];
            return r ? [ t.createElement(r[1]) ] : (r = x.buildFragment([ e ], t, i), i && x(i).remove(), 
            x.merge([], r.childNodes));
        },
        parseJSON: function(n) {
            return e.JSON && e.JSON.parse ? e.JSON.parse(n) : null === n ? n : "string" == typeof n && (n = x.trim(n), 
            n && E.test(n.replace(A, "@").replace(j, "]").replace(S, ""))) ? Function("return " + n)() : (x.error("Invalid JSON: " + n), 
            t);
        },
        parseXML: function(n) {
            var r, i;
            if (!n || "string" != typeof n) return null;
            try {
                e.DOMParser ? (i = new DOMParser(), r = i.parseFromString(n, "text/xml")) : (r = new ActiveXObject("Microsoft.XMLDOM"), 
                r.async = "false", r.loadXML(n));
            } catch (o) {
                r = t;
            }
            return r && r.documentElement && !r.getElementsByTagName("parsererror").length || x.error("Invalid XML: " + n), 
            r;
        },
        noop: function() {},
        globalEval: function(t) {
            t && x.trim(t) && (e.execScript || function(t) {
                e.eval.call(e, t);
            })(t);
        },
        camelCase: function(e) {
            return e.replace(D, "ms-").replace(L, H);
        },
        nodeName: function(e, t) {
            return e.nodeName && e.nodeName.toLowerCase() === t.toLowerCase();
        },
        each: function(e, t, n) {
            var r, i = 0, o = e.length, a = M(e);
            if (n) {
                if (a) {
                    for (;o > i; i++) if (r = t.apply(e[i], n), r === !1) break;
                } else for (i in e) if (r = t.apply(e[i], n), r === !1) break;
            } else if (a) {
                for (;o > i; i++) if (r = t.call(e[i], i, e[i]), r === !1) break;
            } else for (i in e) if (r = t.call(e[i], i, e[i]), r === !1) break;
            return e;
        },
        trim: b && !b.call("﻿ ") ? function(e) {
            return null == e ? "" : b.call(e);
        } : function(e) {
            return null == e ? "" : (e + "").replace(C, "");
        },
        makeArray: function(e, t) {
            var n = t || [];
            return null != e && (M(Object(e)) ? x.merge(n, "string" == typeof e ? [ e ] : e) : h.call(n, e)), 
            n;
        },
        inArray: function(e, t, n) {
            var r;
            if (t) {
                if (m) return m.call(t, e, n);
                for (r = t.length, n = n ? 0 > n ? Math.max(0, r + n) : n : 0; r > n; n++) if (n in t && t[n] === e) return n;
            }
            return -1;
        },
        merge: function(e, n) {
            var r = n.length, i = e.length, o = 0;
            if ("number" == typeof r) for (;r > o; o++) e[i++] = n[o]; else while (n[o] !== t) e[i++] = n[o++];
            return e.length = i, e;
        },
        grep: function(e, t, n) {
            var r, i = [], o = 0, a = e.length;
            for (n = !!n; a > o; o++) r = !!t(e[o], o), n !== r && i.push(e[o]);
            return i;
        },
        map: function(e, t, n) {
            var r, i = 0, o = e.length, a = M(e), s = [];
            if (a) for (;o > i; i++) r = t(e[i], i, n), null != r && (s[s.length] = r); else for (i in e) r = t(e[i], i, n), 
            null != r && (s[s.length] = r);
            return d.apply([], s);
        },
        guid: 1,
        proxy: function(e, n) {
            var r, i, o;
            return "string" == typeof n && (o = e[n], n = e, e = o), x.isFunction(e) ? (r = g.call(arguments, 2), 
            i = function() {
                return e.apply(n || this, r.concat(g.call(arguments)));
            }, i.guid = e.guid = e.guid || x.guid++, i) : t;
        },
        access: function(e, n, r, i, o, a, s) {
            var l = 0, u = e.length, c = null == r;
            if ("object" === x.type(r)) {
                o = !0;
                for (l in r) x.access(e, n, l, r[l], !0, a, s);
            } else if (i !== t && (o = !0, x.isFunction(i) || (s = !0), c && (s ? (n.call(e, i), 
            n = null) : (c = n, n = function(e, t, n) {
                return c.call(x(e), n);
            })), n)) for (;u > l; l++) n(e[l], r, s ? i : i.call(e[l], l, n(e[l], r)));
            return o ? e : c ? n.call(e) : u ? n(e[0], r) : a;
        },
        now: function() {
            return new Date().getTime();
        },
        swap: function(e, t, n, r) {
            var i, o, a = {};
            for (o in t) a[o] = e.style[o], e.style[o] = t[o];
            i = n.apply(e, r || []);
            for (o in t) e.style[o] = a[o];
            return i;
        }
    }), x.ready.promise = function(t) {
        if (!n) if (n = x.Deferred(), "complete" === a.readyState) setTimeout(x.ready); else if (a.addEventListener) a.addEventListener("DOMContentLoaded", q, !1), 
        e.addEventListener("load", q, !1); else {
            a.attachEvent("onreadystatechange", q), e.attachEvent("onload", q);
            var r = !1;
            try {
                r = null == e.frameElement && a.documentElement;
            } catch (i) {}
            r && r.doScroll && function o() {
                if (!x.isReady) {
                    try {
                        r.doScroll("left");
                    } catch (e) {
                        return setTimeout(o, 50);
                    }
                    _(), x.ready();
                }
            }();
        }
        return n.promise(t);
    }, x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(e, t) {
        c["[object " + t + "]"] = t.toLowerCase();
    });
    function M(e) {
        var t = e.length, n = x.type(e);
        return x.isWindow(e) ? !1 : 1 === e.nodeType && t ? !0 : "array" === n || "function" !== n && (0 === t || "number" == typeof t && t > 0 && t - 1 in e);
    }
    r = x(a), function(e, t) {
        var n, r, i, o, a, s, l, u, c, p, f, d, h, g, m, y, v, b = "sizzle" + -new Date(), w = e.document, T = 0, C = 0, N = st(), k = st(), E = st(), S = !1, A = function(e, t) {
            return e === t ? (S = !0, 0) : 0;
        }, j = typeof t, D = 1 << 31, L = {}.hasOwnProperty, H = [], q = H.pop, _ = H.push, M = H.push, O = H.slice, F = H.indexOf || function(e) {
            var t = 0, n = this.length;
            for (;n > t; t++) if (this[t] === e) return t;
            return -1;
        }, B = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", P = "[\\x20\\t\\r\\n\\f]", R = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", W = R.replace("w", "w#"), $ = "\\[" + P + "*(" + R + ")" + P + "*(?:([*^$|!~]?=)" + P + "*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|(" + W + ")|)|)" + P + "*\\]", I = ":(" + R + ")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|" + $.replace(3, 8) + ")*)|.*)\\)|)", z = RegExp("^" + P + "+|((?:^|[^\\\\])(?:\\\\.)*)" + P + "+$", "g"), X = RegExp("^" + P + "*," + P + "*"), U = RegExp("^" + P + "*([>+~]|" + P + ")" + P + "*"), V = RegExp(P + "*[+~]"), Y = RegExp("=" + P + "*([^\\]'\"]*)" + P + "*\\]", "g"), J = RegExp(I), G = RegExp("^" + W + "$"), Q = {
            ID: RegExp("^#(" + R + ")"),
            CLASS: RegExp("^\\.(" + R + ")"),
            TAG: RegExp("^(" + R.replace("w", "w*") + ")"),
            ATTR: RegExp("^" + $),
            PSEUDO: RegExp("^" + I),
            CHILD: RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + P + "*(even|odd|(([+-]|)(\\d*)n|)" + P + "*(?:([+-]|)" + P + "*(\\d+)|))" + P + "*\\)|)", "i"),
            bool: RegExp("^(?:" + B + ")$", "i"),
            needsContext: RegExp("^" + P + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + P + "*((?:-\\d)?\\d*)" + P + "*\\)|)(?=[^-]|$)", "i")
        }, K = /^[^{]+\{\s*\[native \w/, Z = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, et = /^(?:input|select|textarea|button)$/i, tt = /^h\d$/i, nt = /'|\\/g, rt = RegExp("\\\\([\\da-f]{1,6}" + P + "?|(" + P + ")|.)", "ig"), it = function(e, t, n) {
            var r = "0x" + t - 65536;
            return r !== r || n ? t : 0 > r ? String.fromCharCode(r + 65536) : String.fromCharCode(55296 | r >> 10, 56320 | 1023 & r);
        };
        try {
            M.apply(H = O.call(w.childNodes), w.childNodes), H[w.childNodes.length].nodeType;
        } catch (ot) {
            M = {
                apply: H.length ? function(e, t) {
                    _.apply(e, O.call(t));
                } : function(e, t) {
                    var n = e.length, r = 0;
                    while (e[n++] = t[r++]) ;
                    e.length = n - 1;
                }
            };
        }
        function at(e, t, n, i) {
            var o, a, s, l, u, c, d, m, y, x;
            if ((t ? t.ownerDocument || t : w) !== f && p(t), t = t || f, n = n || [], !e || "string" != typeof e) return n;
            if (1 !== (l = t.nodeType) && 9 !== l) return [];
            if (h && !i) {
                if (o = Z.exec(e)) if (s = o[1]) {
                    if (9 === l) {
                        if (a = t.getElementById(s), !a || !a.parentNode) return n;
                        if (a.id === s) return n.push(a), n;
                    } else if (t.ownerDocument && (a = t.ownerDocument.getElementById(s)) && v(t, a) && a.id === s) return n.push(a), 
                    n;
                } else {
                    if (o[2]) return M.apply(n, t.getElementsByTagName(e)), n;
                    if ((s = o[3]) && r.getElementsByClassName && t.getElementsByClassName) return M.apply(n, t.getElementsByClassName(s)), 
                    n;
                }
                if (r.qsa && (!g || !g.test(e))) {
                    if (m = d = b, y = t, x = 9 === l && e, 1 === l && "object" !== t.nodeName.toLowerCase()) {
                        c = mt(e), (d = t.getAttribute("id")) ? m = d.replace(nt, "\\$&") : t.setAttribute("id", m), 
                        m = "[id='" + m + "'] ", u = c.length;
                        while (u--) c[u] = m + yt(c[u]);
                        y = V.test(e) && t.parentNode || t, x = c.join(",");
                    }
                    if (x) try {
                        return M.apply(n, y.querySelectorAll(x)), n;
                    } catch (T) {} finally {
                        d || t.removeAttribute("id");
                    }
                }
            }
            return kt(e.replace(z, "$1"), t, n, i);
        }
        function st() {
            var e = [];
            function t(n, r) {
                return e.push(n += " ") > o.cacheLength && delete t[e.shift()], t[n] = r;
            }
            return t;
        }
        function lt(e) {
            return e[b] = !0, e;
        }
        function ut(e) {
            var t = f.createElement("div");
            try {
                return !!e(t);
            } catch (n) {
                return !1;
            } finally {
                t.parentNode && t.parentNode.removeChild(t), t = null;
            }
        }
        function ct(e, t) {
            var n = e.split("|"), r = e.length;
            while (r--) o.attrHandle[n[r]] = t;
        }
        function pt(e, t) {
            var n = t && e, r = n && 1 === e.nodeType && 1 === t.nodeType && (~t.sourceIndex || D) - (~e.sourceIndex || D);
            if (r) return r;
            if (n) while (n = n.nextSibling) if (n === t) return -1;
            return e ? 1 : -1;
        }
        function ft(e) {
            return function(t) {
                var n = t.nodeName.toLowerCase();
                return "input" === n && t.type === e;
            };
        }
        function dt(e) {
            return function(t) {
                var n = t.nodeName.toLowerCase();
                return ("input" === n || "button" === n) && t.type === e;
            };
        }
        function ht(e) {
            return lt(function(t) {
                return t = +t, lt(function(n, r) {
                    var i, o = e([], n.length, t), a = o.length;
                    while (a--) n[i = o[a]] && (n[i] = !(r[i] = n[i]));
                });
            });
        }
        s = at.isXML = function(e) {
            var t = e && (e.ownerDocument || e).documentElement;
            return t ? "HTML" !== t.nodeName : !1;
        }, r = at.support = {}, p = at.setDocument = function(e) {
            var n = e ? e.ownerDocument || e : w, i = n.defaultView;
            return n !== f && 9 === n.nodeType && n.documentElement ? (f = n, d = n.documentElement, 
            h = !s(n), i && i.attachEvent && i !== i.top && i.attachEvent("onbeforeunload", function() {
                p();
            }), r.attributes = ut(function(e) {
                return e.className = "i", !e.getAttribute("className");
            }), r.getElementsByTagName = ut(function(e) {
                return e.appendChild(n.createComment("")), !e.getElementsByTagName("*").length;
            }), r.getElementsByClassName = ut(function(e) {
                return e.innerHTML = "<div class='a'></div><div class='a i'></div>", e.firstChild.className = "i", 
                2 === e.getElementsByClassName("i").length;
            }), r.getById = ut(function(e) {
                return d.appendChild(e).id = b, !n.getElementsByName || !n.getElementsByName(b).length;
            }), r.getById ? (o.find.ID = function(e, t) {
                if (typeof t.getElementById !== j && h) {
                    var n = t.getElementById(e);
                    return n && n.parentNode ? [ n ] : [];
                }
            }, o.filter.ID = function(e) {
                var t = e.replace(rt, it);
                return function(e) {
                    return e.getAttribute("id") === t;
                };
            }) : (delete o.find.ID, o.filter.ID = function(e) {
                var t = e.replace(rt, it);
                return function(e) {
                    var n = typeof e.getAttributeNode !== j && e.getAttributeNode("id");
                    return n && n.value === t;
                };
            }), o.find.TAG = r.getElementsByTagName ? function(e, n) {
                return typeof n.getElementsByTagName !== j ? n.getElementsByTagName(e) : t;
            } : function(e, t) {
                var n, r = [], i = 0, o = t.getElementsByTagName(e);
                if ("*" === e) {
                    while (n = o[i++]) 1 === n.nodeType && r.push(n);
                    return r;
                }
                return o;
            }, o.find.CLASS = r.getElementsByClassName && function(e, n) {
                return typeof n.getElementsByClassName !== j && h ? n.getElementsByClassName(e) : t;
            }, m = [], g = [], (r.qsa = K.test(n.querySelectorAll)) && (ut(function(e) {
                e.innerHTML = "<select><option selected=''></option></select>", e.querySelectorAll("[selected]").length || g.push("\\[" + P + "*(?:value|" + B + ")"), 
                e.querySelectorAll(":checked").length || g.push(":checked");
            }), ut(function(e) {
                var t = n.createElement("input");
                t.setAttribute("type", "hidden"), e.appendChild(t).setAttribute("t", ""), e.querySelectorAll("[t^='']").length && g.push("[*^$]=" + P + "*(?:''|\"\")"), 
                e.querySelectorAll(":enabled").length || g.push(":enabled", ":disabled"), e.querySelectorAll("*,:x"), 
                g.push(",.*:");
            })), (r.matchesSelector = K.test(y = d.webkitMatchesSelector || d.mozMatchesSelector || d.oMatchesSelector || d.msMatchesSelector)) && ut(function(e) {
                r.disconnectedMatch = y.call(e, "div"), y.call(e, "[s!='']:x"), m.push("!=", I);
            }), g = g.length && RegExp(g.join("|")), m = m.length && RegExp(m.join("|")), v = K.test(d.contains) || d.compareDocumentPosition ? function(e, t) {
                var n = 9 === e.nodeType ? e.documentElement : e, r = t && t.parentNode;
                return e === r || !(!r || 1 !== r.nodeType || !(n.contains ? n.contains(r) : e.compareDocumentPosition && 16 & e.compareDocumentPosition(r)));
            } : function(e, t) {
                if (t) while (t = t.parentNode) if (t === e) return !0;
                return !1;
            }, A = d.compareDocumentPosition ? function(e, t) {
                if (e === t) return S = !0, 0;
                var i = t.compareDocumentPosition && e.compareDocumentPosition && e.compareDocumentPosition(t);
                return i ? 1 & i || !r.sortDetached && t.compareDocumentPosition(e) === i ? e === n || v(w, e) ? -1 : t === n || v(w, t) ? 1 : c ? F.call(c, e) - F.call(c, t) : 0 : 4 & i ? -1 : 1 : e.compareDocumentPosition ? -1 : 1;
            } : function(e, t) {
                var r, i = 0, o = e.parentNode, a = t.parentNode, s = [ e ], l = [ t ];
                if (e === t) return S = !0, 0;
                if (!o || !a) return e === n ? -1 : t === n ? 1 : o ? -1 : a ? 1 : c ? F.call(c, e) - F.call(c, t) : 0;
                if (o === a) return pt(e, t);
                r = e;
                while (r = r.parentNode) s.unshift(r);
                r = t;
                while (r = r.parentNode) l.unshift(r);
                while (s[i] === l[i]) i++;
                return i ? pt(s[i], l[i]) : s[i] === w ? -1 : l[i] === w ? 1 : 0;
            }, n) : f;
        }, at.matches = function(e, t) {
            return at(e, null, null, t);
        }, at.matchesSelector = function(e, t) {
            if ((e.ownerDocument || e) !== f && p(e), t = t.replace(Y, "='$1']"), !(!r.matchesSelector || !h || m && m.test(t) || g && g.test(t))) try {
                var n = y.call(e, t);
                if (n || r.disconnectedMatch || e.document && 11 !== e.document.nodeType) return n;
            } catch (i) {}
            return at(t, f, null, [ e ]).length > 0;
        }, at.contains = function(e, t) {
            return (e.ownerDocument || e) !== f && p(e), v(e, t);
        }, at.attr = function(e, n) {
            (e.ownerDocument || e) !== f && p(e);
            var i = o.attrHandle[n.toLowerCase()], a = i && L.call(o.attrHandle, n.toLowerCase()) ? i(e, n, !h) : t;
            return a === t ? r.attributes || !h ? e.getAttribute(n) : (a = e.getAttributeNode(n)) && a.specified ? a.value : null : a;
        }, at.error = function(e) {
            throw Error("Syntax error, unrecognized expression: " + e);
        }, at.uniqueSort = function(e) {
            var t, n = [], i = 0, o = 0;
            if (S = !r.detectDuplicates, c = !r.sortStable && e.slice(0), e.sort(A), S) {
                while (t = e[o++]) t === e[o] && (i = n.push(o));
                while (i--) e.splice(n[i], 1);
            }
            return e;
        }, a = at.getText = function(e) {
            var t, n = "", r = 0, i = e.nodeType;
            if (i) {
                if (1 === i || 9 === i || 11 === i) {
                    if ("string" == typeof e.textContent) return e.textContent;
                    for (e = e.firstChild; e; e = e.nextSibling) n += a(e);
                } else if (3 === i || 4 === i) return e.nodeValue;
            } else for (;t = e[r]; r++) n += a(t);
            return n;
        }, o = at.selectors = {
            cacheLength: 50,
            createPseudo: lt,
            match: Q,
            attrHandle: {},
            find: {},
            relative: {
                ">": {
                    dir: "parentNode",
                    first: !0
                },
                " ": {
                    dir: "parentNode"
                },
                "+": {
                    dir: "previousSibling",
                    first: !0
                },
                "~": {
                    dir: "previousSibling"
                }
            },
            preFilter: {
                ATTR: function(e) {
                    return e[1] = e[1].replace(rt, it), e[3] = (e[4] || e[5] || "").replace(rt, it), 
                    "~=" === e[2] && (e[3] = " " + e[3] + " "), e.slice(0, 4);
                },
                CHILD: function(e) {
                    return e[1] = e[1].toLowerCase(), "nth" === e[1].slice(0, 3) ? (e[3] || at.error(e[0]), 
                    e[4] = +(e[4] ? e[5] + (e[6] || 1) : 2 * ("even" === e[3] || "odd" === e[3])), e[5] = +(e[7] + e[8] || "odd" === e[3])) : e[3] && at.error(e[0]), 
                    e;
                },
                PSEUDO: function(e) {
                    var n, r = !e[5] && e[2];
                    return Q.CHILD.test(e[0]) ? null : (e[3] && e[4] !== t ? e[2] = e[4] : r && J.test(r) && (n = mt(r, !0)) && (n = r.indexOf(")", r.length - n) - r.length) && (e[0] = e[0].slice(0, n), 
                    e[2] = r.slice(0, n)), e.slice(0, 3));
                }
            },
            filter: {
                TAG: function(e) {
                    var t = e.replace(rt, it).toLowerCase();
                    return "*" === e ? function() {
                        return !0;
                    } : function(e) {
                        return e.nodeName && e.nodeName.toLowerCase() === t;
                    };
                },
                CLASS: function(e) {
                    var t = N[e + " "];
                    return t || (t = RegExp("(^|" + P + ")" + e + "(" + P + "|$)")) && N(e, function(e) {
                        return t.test("string" == typeof e.className && e.className || typeof e.getAttribute !== j && e.getAttribute("class") || "");
                    });
                },
                ATTR: function(e, t, n) {
                    return function(r) {
                        var i = at.attr(r, e);
                        return null == i ? "!=" === t : t ? (i += "", "=" === t ? i === n : "!=" === t ? i !== n : "^=" === t ? n && 0 === i.indexOf(n) : "*=" === t ? n && i.indexOf(n) > -1 : "$=" === t ? n && i.slice(-n.length) === n : "~=" === t ? (" " + i + " ").indexOf(n) > -1 : "|=" === t ? i === n || i.slice(0, n.length + 1) === n + "-" : !1) : !0;
                    };
                },
                CHILD: function(e, t, n, r, i) {
                    var o = "nth" !== e.slice(0, 3), a = "last" !== e.slice(-4), s = "of-type" === t;
                    return 1 === r && 0 === i ? function(e) {
                        return !!e.parentNode;
                    } : function(t, n, l) {
                        var u, c, p, f, d, h, g = o !== a ? "nextSibling" : "previousSibling", m = t.parentNode, y = s && t.nodeName.toLowerCase(), v = !l && !s;
                        if (m) {
                            if (o) {
                                while (g) {
                                    p = t;
                                    while (p = p[g]) if (s ? p.nodeName.toLowerCase() === y : 1 === p.nodeType) return !1;
                                    h = g = "only" === e && !h && "nextSibling";
                                }
                                return !0;
                            }
                            if (h = [ a ? m.firstChild : m.lastChild ], a && v) {
                                c = m[b] || (m[b] = {}), u = c[e] || [], d = u[0] === T && u[1], f = u[0] === T && u[2], 
                                p = d && m.childNodes[d];
                                while (p = ++d && p && p[g] || (f = d = 0) || h.pop()) if (1 === p.nodeType && ++f && p === t) {
                                    c[e] = [ T, d, f ];
                                    break;
                                }
                            } else if (v && (u = (t[b] || (t[b] = {}))[e]) && u[0] === T) f = u[1]; else while (p = ++d && p && p[g] || (f = d = 0) || h.pop()) if ((s ? p.nodeName.toLowerCase() === y : 1 === p.nodeType) && ++f && (v && ((p[b] || (p[b] = {}))[e] = [ T, f ]), 
                            p === t)) break;
                            return f -= i, f === r || 0 === f % r && f / r >= 0;
                        }
                    };
                },
                PSEUDO: function(e, t) {
                    var n, r = o.pseudos[e] || o.setFilters[e.toLowerCase()] || at.error("unsupported pseudo: " + e);
                    return r[b] ? r(t) : r.length > 1 ? (n = [ e, e, "", t ], o.setFilters.hasOwnProperty(e.toLowerCase()) ? lt(function(e, n) {
                        var i, o = r(e, t), a = o.length;
                        while (a--) i = F.call(e, o[a]), e[i] = !(n[i] = o[a]);
                    }) : function(e) {
                        return r(e, 0, n);
                    }) : r;
                }
            },
            pseudos: {
                not: lt(function(e) {
                    var t = [], n = [], r = l(e.replace(z, "$1"));
                    return r[b] ? lt(function(e, t, n, i) {
                        var o, a = r(e, null, i, []), s = e.length;
                        while (s--) (o = a[s]) && (e[s] = !(t[s] = o));
                    }) : function(e, i, o) {
                        return t[0] = e, r(t, null, o, n), !n.pop();
                    };
                }),
                has: lt(function(e) {
                    return function(t) {
                        return at(e, t).length > 0;
                    };
                }),
                contains: lt(function(e) {
                    return function(t) {
                        return (t.textContent || t.innerText || a(t)).indexOf(e) > -1;
                    };
                }),
                lang: lt(function(e) {
                    return G.test(e || "") || at.error("unsupported lang: " + e), e = e.replace(rt, it).toLowerCase(), 
                    function(t) {
                        var n;
                        do if (n = h ? t.lang : t.getAttribute("xml:lang") || t.getAttribute("lang")) return n = n.toLowerCase(), 
                        n === e || 0 === n.indexOf(e + "-"); while ((t = t.parentNode) && 1 === t.nodeType);
                        return !1;
                    };
                }),
                target: function(t) {
                    var n = e.location && e.location.hash;
                    return n && n.slice(1) === t.id;
                },
                root: function(e) {
                    return e === d;
                },
                focus: function(e) {
                    return e === f.activeElement && (!f.hasFocus || f.hasFocus()) && !!(e.type || e.href || ~e.tabIndex);
                },
                enabled: function(e) {
                    return e.disabled === !1;
                },
                disabled: function(e) {
                    return e.disabled === !0;
                },
                checked: function(e) {
                    var t = e.nodeName.toLowerCase();
                    return "input" === t && !!e.checked || "option" === t && !!e.selected;
                },
                selected: function(e) {
                    return e.parentNode && e.parentNode.selectedIndex, e.selected === !0;
                },
                empty: function(e) {
                    for (e = e.firstChild; e; e = e.nextSibling) if (e.nodeName > "@" || 3 === e.nodeType || 4 === e.nodeType) return !1;
                    return !0;
                },
                parent: function(e) {
                    return !o.pseudos.empty(e);
                },
                header: function(e) {
                    return tt.test(e.nodeName);
                },
                input: function(e) {
                    return et.test(e.nodeName);
                },
                button: function(e) {
                    var t = e.nodeName.toLowerCase();
                    return "input" === t && "button" === e.type || "button" === t;
                },
                text: function(e) {
                    var t;
                    return "input" === e.nodeName.toLowerCase() && "text" === e.type && (null == (t = e.getAttribute("type")) || t.toLowerCase() === e.type);
                },
                first: ht(function() {
                    return [ 0 ];
                }),
                last: ht(function(e, t) {
                    return [ t - 1 ];
                }),
                eq: ht(function(e, t, n) {
                    return [ 0 > n ? n + t : n ];
                }),
                even: ht(function(e, t) {
                    var n = 0;
                    for (;t > n; n += 2) e.push(n);
                    return e;
                }),
                odd: ht(function(e, t) {
                    var n = 1;
                    for (;t > n; n += 2) e.push(n);
                    return e;
                }),
                lt: ht(function(e, t, n) {
                    var r = 0 > n ? n + t : n;
                    for (;--r >= 0; ) e.push(r);
                    return e;
                }),
                gt: ht(function(e, t, n) {
                    var r = 0 > n ? n + t : n;
                    for (;t > ++r; ) e.push(r);
                    return e;
                })
            }
        }, o.pseudos.nth = o.pseudos.eq;
        for (n in {
            radio: !0,
            checkbox: !0,
            file: !0,
            password: !0,
            image: !0
        }) o.pseudos[n] = ft(n);
        for (n in {
            submit: !0,
            reset: !0
        }) o.pseudos[n] = dt(n);
        function gt() {}
        gt.prototype = o.filters = o.pseudos, o.setFilters = new gt();
        function mt(e, t) {
            var n, r, i, a, s, l, u, c = k[e + " "];
            if (c) return t ? 0 : c.slice(0);
            s = e, l = [], u = o.preFilter;
            while (s) {
                (!n || (r = X.exec(s))) && (r && (s = s.slice(r[0].length) || s), l.push(i = [])), 
                n = !1, (r = U.exec(s)) && (n = r.shift(), i.push({
                    value: n,
                    type: r[0].replace(z, " ")
                }), s = s.slice(n.length));
                for (a in o.filter) !(r = Q[a].exec(s)) || u[a] && !(r = u[a](r)) || (n = r.shift(), 
                i.push({
                    value: n,
                    type: a,
                    matches: r
                }), s = s.slice(n.length));
                if (!n) break;
            }
            return t ? s.length : s ? at.error(e) : k(e, l).slice(0);
        }
        function yt(e) {
            var t = 0, n = e.length, r = "";
            for (;n > t; t++) r += e[t].value;
            return r;
        }
        function vt(e, t, n) {
            var r = t.dir, o = n && "parentNode" === r, a = C++;
            return t.first ? function(t, n, i) {
                while (t = t[r]) if (1 === t.nodeType || o) return e(t, n, i);
            } : function(t, n, s) {
                var l, u, c, p = T + " " + a;
                if (s) {
                    while (t = t[r]) if ((1 === t.nodeType || o) && e(t, n, s)) return !0;
                } else while (t = t[r]) if (1 === t.nodeType || o) if (c = t[b] || (t[b] = {}), 
                (u = c[r]) && u[0] === p) {
                    if ((l = u[1]) === !0 || l === i) return l === !0;
                } else if (u = c[r] = [ p ], u[1] = e(t, n, s) || i, u[1] === !0) return !0;
            };
        }
        function bt(e) {
            return e.length > 1 ? function(t, n, r) {
                var i = e.length;
                while (i--) if (!e[i](t, n, r)) return !1;
                return !0;
            } : e[0];
        }
        function xt(e, t, n, r, i) {
            var o, a = [], s = 0, l = e.length, u = null != t;
            for (;l > s; s++) (o = e[s]) && (!n || n(o, r, i)) && (a.push(o), u && t.push(s));
            return a;
        }
        function wt(e, t, n, r, i, o) {
            return r && !r[b] && (r = wt(r)), i && !i[b] && (i = wt(i, o)), lt(function(o, a, s, l) {
                var u, c, p, f = [], d = [], h = a.length, g = o || Nt(t || "*", s.nodeType ? [ s ] : s, []), m = !e || !o && t ? g : xt(g, f, e, s, l), y = n ? i || (o ? e : h || r) ? [] : a : m;
                if (n && n(m, y, s, l), r) {
                    u = xt(y, d), r(u, [], s, l), c = u.length;
                    while (c--) (p = u[c]) && (y[d[c]] = !(m[d[c]] = p));
                }
                if (o) {
                    if (i || e) {
                        if (i) {
                            u = [], c = y.length;
                            while (c--) (p = y[c]) && u.push(m[c] = p);
                            i(null, y = [], u, l);
                        }
                        c = y.length;
                        while (c--) (p = y[c]) && (u = i ? F.call(o, p) : f[c]) > -1 && (o[u] = !(a[u] = p));
                    }
                } else y = xt(y === a ? y.splice(h, y.length) : y), i ? i(null, a, y, l) : M.apply(a, y);
            });
        }
        function Tt(e) {
            var t, n, r, i = e.length, a = o.relative[e[0].type], s = a || o.relative[" "], l = a ? 1 : 0, c = vt(function(e) {
                return e === t;
            }, s, !0), p = vt(function(e) {
                return F.call(t, e) > -1;
            }, s, !0), f = [ function(e, n, r) {
                return !a && (r || n !== u) || ((t = n).nodeType ? c(e, n, r) : p(e, n, r));
            } ];
            for (;i > l; l++) if (n = o.relative[e[l].type]) f = [ vt(bt(f), n) ]; else {
                if (n = o.filter[e[l].type].apply(null, e[l].matches), n[b]) {
                    for (r = ++l; i > r; r++) if (o.relative[e[r].type]) break;
                    return wt(l > 1 && bt(f), l > 1 && yt(e.slice(0, l - 1).concat({
                        value: " " === e[l - 2].type ? "*" : ""
                    })).replace(z, "$1"), n, r > l && Tt(e.slice(l, r)), i > r && Tt(e = e.slice(r)), i > r && yt(e));
                }
                f.push(n);
            }
            return bt(f);
        }
        function Ct(e, t) {
            var n = 0, r = t.length > 0, a = e.length > 0, s = function(s, l, c, p, d) {
                var h, g, m, y = [], v = 0, b = "0", x = s && [], w = null != d, C = u, N = s || a && o.find.TAG("*", d && l.parentNode || l), k = T += null == C ? 1 : Math.random() || .1;
                for (w && (u = l !== f && l, i = n); null != (h = N[b]); b++) {
                    if (a && h) {
                        g = 0;
                        while (m = e[g++]) if (m(h, l, c)) {
                            p.push(h);
                            break;
                        }
                        w && (T = k, i = ++n);
                    }
                    r && ((h = !m && h) && v--, s && x.push(h));
                }
                if (v += b, r && b !== v) {
                    g = 0;
                    while (m = t[g++]) m(x, y, l, c);
                    if (s) {
                        if (v > 0) while (b--) x[b] || y[b] || (y[b] = q.call(p));
                        y = xt(y);
                    }
                    M.apply(p, y), w && !s && y.length > 0 && v + t.length > 1 && at.uniqueSort(p);
                }
                return w && (T = k, u = C), x;
            };
            return r ? lt(s) : s;
        }
        l = at.compile = function(e, t) {
            var n, r = [], i = [], o = E[e + " "];
            if (!o) {
                t || (t = mt(e)), n = t.length;
                while (n--) o = Tt(t[n]), o[b] ? r.push(o) : i.push(o);
                o = E(e, Ct(i, r));
            }
            return o;
        };
        function Nt(e, t, n) {
            var r = 0, i = t.length;
            for (;i > r; r++) at(e, t[r], n);
            return n;
        }
        function kt(e, t, n, i) {
            var a, s, u, c, p, f = mt(e);
            if (!i && 1 === f.length) {
                if (s = f[0] = f[0].slice(0), s.length > 2 && "ID" === (u = s[0]).type && r.getById && 9 === t.nodeType && h && o.relative[s[1].type]) {
                    if (t = (o.find.ID(u.matches[0].replace(rt, it), t) || [])[0], !t) return n;
                    e = e.slice(s.shift().value.length);
                }
                a = Q.needsContext.test(e) ? 0 : s.length;
                while (a--) {
                    if (u = s[a], o.relative[c = u.type]) break;
                    if ((p = o.find[c]) && (i = p(u.matches[0].replace(rt, it), V.test(s[0].type) && t.parentNode || t))) {
                        if (s.splice(a, 1), e = i.length && yt(s), !e) return M.apply(n, i), n;
                        break;
                    }
                }
            }
            return l(e, f)(i, t, !h, n, V.test(e)), n;
        }
        r.sortStable = b.split("").sort(A).join("") === b, r.detectDuplicates = S, p(), 
        r.sortDetached = ut(function(e) {
            return 1 & e.compareDocumentPosition(f.createElement("div"));
        }), ut(function(e) {
            return e.innerHTML = "<a href='#'></a>", "#" === e.firstChild.getAttribute("href");
        }) || ct("type|href|height|width", function(e, n, r) {
            return r ? t : e.getAttribute(n, "type" === n.toLowerCase() ? 1 : 2);
        }), r.attributes && ut(function(e) {
            return e.innerHTML = "<input/>", e.firstChild.setAttribute("value", ""), "" === e.firstChild.getAttribute("value");
        }) || ct("value", function(e, n, r) {
            return r || "input" !== e.nodeName.toLowerCase() ? t : e.defaultValue;
        }), ut(function(e) {
            return null == e.getAttribute("disabled");
        }) || ct(B, function(e, n, r) {
            var i;
            return r ? t : (i = e.getAttributeNode(n)) && i.specified ? i.value : e[n] === !0 ? n.toLowerCase() : null;
        }), x.find = at, x.expr = at.selectors, x.expr[":"] = x.expr.pseudos, x.unique = at.uniqueSort, 
        x.text = at.getText, x.isXMLDoc = at.isXML, x.contains = at.contains;
    }(e);
    var O = {};
    function F(e) {
        var t = O[e] = {};
        return x.each(e.match(T) || [], function(e, n) {
            t[n] = !0;
        }), t;
    }
    x.Callbacks = function(e) {
        e = "string" == typeof e ? O[e] || F(e) : x.extend({}, e);
        var n, r, i, o, a, s, l = [], u = !e.once && [], c = function(t) {
            for (r = e.memory && t, i = !0, a = s || 0, s = 0, o = l.length, n = !0; l && o > a; a++) if (l[a].apply(t[0], t[1]) === !1 && e.stopOnFalse) {
                r = !1;
                break;
            }
            n = !1, l && (u ? u.length && c(u.shift()) : r ? l = [] : p.disable());
        }, p = {
            add: function() {
                if (l) {
                    var t = l.length;
                    (function i(t) {
                        x.each(t, function(t, n) {
                            var r = x.type(n);
                            "function" === r ? e.unique && p.has(n) || l.push(n) : n && n.length && "string" !== r && i(n);
                        });
                    })(arguments), n ? o = l.length : r && (s = t, c(r));
                }
                return this;
            },
            remove: function() {
                return l && x.each(arguments, function(e, t) {
                    var r;
                    while ((r = x.inArray(t, l, r)) > -1) l.splice(r, 1), n && (o >= r && o--, a >= r && a--);
                }), this;
            },
            has: function(e) {
                return e ? x.inArray(e, l) > -1 : !(!l || !l.length);
            },
            empty: function() {
                return l = [], o = 0, this;
            },
            disable: function() {
                return l = u = r = t, this;
            },
            disabled: function() {
                return !l;
            },
            lock: function() {
                return u = t, r || p.disable(), this;
            },
            locked: function() {
                return !u;
            },
            fireWith: function(e, t) {
                return !l || i && !u || (t = t || [], t = [ e, t.slice ? t.slice() : t ], n ? u.push(t) : c(t)), 
                this;
            },
            fire: function() {
                return p.fireWith(this, arguments), this;
            },
            fired: function() {
                return !!i;
            }
        };
        return p;
    }, x.extend({
        Deferred: function(e) {
            var t = [ [ "resolve", "done", x.Callbacks("once memory"), "resolved" ], [ "reject", "fail", x.Callbacks("once memory"), "rejected" ], [ "notify", "progress", x.Callbacks("memory") ] ], n = "pending", r = {
                state: function() {
                    return n;
                },
                always: function() {
                    return i.done(arguments).fail(arguments), this;
                },
                then: function() {
                    var e = arguments;
                    return x.Deferred(function(n) {
                        x.each(t, function(t, o) {
                            var a = o[0], s = x.isFunction(e[t]) && e[t];
                            i[o[1]](function() {
                                var e = s && s.apply(this, arguments);
                                e && x.isFunction(e.promise) ? e.promise().done(n.resolve).fail(n.reject).progress(n.notify) : n[a + "With"](this === r ? n.promise() : this, s ? [ e ] : arguments);
                            });
                        }), e = null;
                    }).promise();
                },
                promise: function(e) {
                    return null != e ? x.extend(e, r) : r;
                }
            }, i = {};
            return r.pipe = r.then, x.each(t, function(e, o) {
                var a = o[2], s = o[3];
                r[o[1]] = a.add, s && a.add(function() {
                    n = s;
                }, t[1 ^ e][2].disable, t[2][2].lock), i[o[0]] = function() {
                    return i[o[0] + "With"](this === i ? r : this, arguments), this;
                }, i[o[0] + "With"] = a.fireWith;
            }), r.promise(i), e && e.call(i, i), i;
        },
        when: function(e) {
            var t = 0, n = g.call(arguments), r = n.length, i = 1 !== r || e && x.isFunction(e.promise) ? r : 0, o = 1 === i ? e : x.Deferred(), a = function(e, t, n) {
                return function(r) {
                    t[e] = this, n[e] = arguments.length > 1 ? g.call(arguments) : r, n === s ? o.notifyWith(t, n) : --i || o.resolveWith(t, n);
                };
            }, s, l, u;
            if (r > 1) for (s = Array(r), l = Array(r), u = Array(r); r > t; t++) n[t] && x.isFunction(n[t].promise) ? n[t].promise().done(a(t, u, n)).fail(o.reject).progress(a(t, l, s)) : --i;
            return i || o.resolveWith(u, n), o.promise();
        }
    }), x.support = function(t) {
        var n, r, o, s, l, u, c, p, f, d = a.createElement("div");
        if (d.setAttribute("className", "t"), d.innerHTML = "  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>", 
        n = d.getElementsByTagName("*") || [], r = d.getElementsByTagName("a")[0], !r || !r.style || !n.length) return t;
        s = a.createElement("select"), u = s.appendChild(a.createElement("option")), o = d.getElementsByTagName("input")[0], 
        r.style.cssText = "top:1px;float:left;opacity:.5", t.getSetAttribute = "t" !== d.className, 
        t.leadingWhitespace = 3 === d.firstChild.nodeType, t.tbody = !d.getElementsByTagName("tbody").length, 
        t.htmlSerialize = !!d.getElementsByTagName("link").length, t.style = /top/.test(r.getAttribute("style")), 
        t.hrefNormalized = "/a" === r.getAttribute("href"), t.opacity = /^0.5/.test(r.style.opacity), 
        t.cssFloat = !!r.style.cssFloat, t.checkOn = !!o.value, t.optSelected = u.selected, 
        t.enctype = !!a.createElement("form").enctype, t.html5Clone = "<:nav></:nav>" !== a.createElement("nav").cloneNode(!0).outerHTML, 
        t.inlineBlockNeedsLayout = !1, t.shrinkWrapBlocks = !1, t.pixelPosition = !1, t.deleteExpando = !0, 
        t.noCloneEvent = !0, t.reliableMarginRight = !0, t.boxSizingReliable = !0, o.checked = !0, 
        t.noCloneChecked = o.cloneNode(!0).checked, s.disabled = !0, t.optDisabled = !u.disabled;
        try {
            delete d.test;
        } catch (h) {
            t.deleteExpando = !1;
        }
        o = a.createElement("input"), o.setAttribute("value", ""), t.input = "" === o.getAttribute("value"), 
        o.value = "t", o.setAttribute("type", "radio"), t.radioValue = "t" === o.value, 
        o.setAttribute("checked", "t"), o.setAttribute("name", "t"), l = a.createDocumentFragment(), 
        l.appendChild(o), t.appendChecked = o.checked, t.checkClone = l.cloneNode(!0).cloneNode(!0).lastChild.checked, 
        d.attachEvent && (d.attachEvent("onclick", function() {
            t.noCloneEvent = !1;
        }), d.cloneNode(!0).click());
        for (f in {
            submit: !0,
            change: !0,
            focusin: !0
        }) d.setAttribute(c = "on" + f, "t"), t[f + "Bubbles"] = c in e || d.attributes[c].expando === !1;
        d.style.backgroundClip = "content-box", d.cloneNode(!0).style.backgroundClip = "", 
        t.clearCloneStyle = "content-box" === d.style.backgroundClip;
        for (f in x(t)) break;
        return t.ownLast = "0" !== f, x(function() {
            var n, r, o, s = "padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;", l = a.getElementsByTagName("body")[0];
            l && (n = a.createElement("div"), n.style.cssText = "border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px", 
            l.appendChild(n).appendChild(d), d.innerHTML = "<table><tr><td></td><td>t</td></tr></table>", 
            o = d.getElementsByTagName("td"), o[0].style.cssText = "padding:0;margin:0;border:0;display:none", 
            p = 0 === o[0].offsetHeight, o[0].style.display = "", o[1].style.display = "none", 
            t.reliableHiddenOffsets = p && 0 === o[0].offsetHeight, d.innerHTML = "", d.style.cssText = "box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;", 
            x.swap(l, null != l.style.zoom ? {
                zoom: 1
            } : {}, function() {
                t.boxSizing = 4 === d.offsetWidth;
            }), e.getComputedStyle && (t.pixelPosition = "1%" !== (e.getComputedStyle(d, null) || {}).top, 
            t.boxSizingReliable = "4px" === (e.getComputedStyle(d, null) || {
                width: "4px"
            }).width, r = d.appendChild(a.createElement("div")), r.style.cssText = d.style.cssText = s, 
            r.style.marginRight = r.style.width = "0", d.style.width = "1px", t.reliableMarginRight = !parseFloat((e.getComputedStyle(r, null) || {}).marginRight)), 
            typeof d.style.zoom !== i && (d.innerHTML = "", d.style.cssText = s + "width:1px;padding:1px;display:inline;zoom:1", 
            t.inlineBlockNeedsLayout = 3 === d.offsetWidth, d.style.display = "block", d.innerHTML = "<div></div>", 
            d.firstChild.style.width = "5px", t.shrinkWrapBlocks = 3 !== d.offsetWidth, t.inlineBlockNeedsLayout && (l.style.zoom = 1)), 
            l.removeChild(n), n = d = o = r = null);
        }), n = s = l = u = r = o = null, t;
    }({});
    var B = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, P = /([A-Z])/g;
    function R(e, n, r, i) {
        if (x.acceptData(e)) {
            var o, a, s = x.expando, l = e.nodeType, u = l ? x.cache : e, c = l ? e[s] : e[s] && s;
            if (c && u[c] && (i || u[c].data) || r !== t || "string" != typeof n) return c || (c = l ? e[s] = p.pop() || x.guid++ : s), 
            u[c] || (u[c] = l ? {} : {
                toJSON: x.noop
            }), ("object" == typeof n || "function" == typeof n) && (i ? u[c] = x.extend(u[c], n) : u[c].data = x.extend(u[c].data, n)), 
            a = u[c], i || (a.data || (a.data = {}), a = a.data), r !== t && (a[x.camelCase(n)] = r), 
            "string" == typeof n ? (o = a[n], null == o && (o = a[x.camelCase(n)])) : o = a, 
            o;
        }
    }
    function W(e, t, n) {
        if (x.acceptData(e)) {
            var r, i, o = e.nodeType, a = o ? x.cache : e, s = o ? e[x.expando] : x.expando;
            if (a[s]) {
                if (t && (r = n ? a[s] : a[s].data)) {
                    x.isArray(t) ? t = t.concat(x.map(t, x.camelCase)) : t in r ? t = [ t ] : (t = x.camelCase(t), 
                    t = t in r ? [ t ] : t.split(" ")), i = t.length;
                    while (i--) delete r[t[i]];
                    if (n ? !I(r) : !x.isEmptyObject(r)) return;
                }
                (n || (delete a[s].data, I(a[s]))) && (o ? x.cleanData([ e ], !0) : x.support.deleteExpando || a != a.window ? delete a[s] : a[s] = null);
            }
        }
    }
    x.extend({
        cache: {},
        noData: {
            applet: !0,
            embed: !0,
            object: "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
        },
        hasData: function(e) {
            return e = e.nodeType ? x.cache[e[x.expando]] : e[x.expando], !!e && !I(e);
        },
        data: function(e, t, n) {
            return R(e, t, n);
        },
        removeData: function(e, t) {
            return W(e, t);
        },
        _data: function(e, t, n) {
            return R(e, t, n, !0);
        },
        _removeData: function(e, t) {
            return W(e, t, !0);
        },
        acceptData: function(e) {
            if (e.nodeType && 1 !== e.nodeType && 9 !== e.nodeType) return !1;
            var t = e.nodeName && x.noData[e.nodeName.toLowerCase()];
            return !t || t !== !0 && e.getAttribute("classid") === t;
        }
    }), x.fn.extend({
        data: function(e, n) {
            var r, i, o = null, a = 0, s = this[0];
            if (e === t) {
                if (this.length && (o = x.data(s), 1 === s.nodeType && !x._data(s, "parsedAttrs"))) {
                    for (r = s.attributes; r.length > a; a++) i = r[a].name, 0 === i.indexOf("data-") && (i = x.camelCase(i.slice(5)), 
                    $(s, i, o[i]));
                    x._data(s, "parsedAttrs", !0);
                }
                return o;
            }
            return "object" == typeof e ? this.each(function() {
                x.data(this, e);
            }) : arguments.length > 1 ? this.each(function() {
                x.data(this, e, n);
            }) : s ? $(s, e, x.data(s, e)) : null;
        },
        removeData: function(e) {
            return this.each(function() {
                x.removeData(this, e);
            });
        }
    });
    function $(e, n, r) {
        if (r === t && 1 === e.nodeType) {
            var i = "data-" + n.replace(P, "-$1").toLowerCase();
            if (r = e.getAttribute(i), "string" == typeof r) {
                try {
                    r = "true" === r ? !0 : "false" === r ? !1 : "null" === r ? null : +r + "" === r ? +r : B.test(r) ? x.parseJSON(r) : r;
                } catch (o) {}
                x.data(e, n, r);
            } else r = t;
        }
        return r;
    }
    function I(e) {
        var t;
        for (t in e) if (("data" !== t || !x.isEmptyObject(e[t])) && "toJSON" !== t) return !1;
        return !0;
    }
    x.extend({
        queue: function(e, n, r) {
            var i;
            return e ? (n = (n || "fx") + "queue", i = x._data(e, n), r && (!i || x.isArray(r) ? i = x._data(e, n, x.makeArray(r)) : i.push(r)), 
            i || []) : t;
        },
        dequeue: function(e, t) {
            t = t || "fx";
            var n = x.queue(e, t), r = n.length, i = n.shift(), o = x._queueHooks(e, t), a = function() {
                x.dequeue(e, t);
            };
            "inprogress" === i && (i = n.shift(), r--), i && ("fx" === t && n.unshift("inprogress"), 
            delete o.stop, i.call(e, a, o)), !r && o && o.empty.fire();
        },
        _queueHooks: function(e, t) {
            var n = t + "queueHooks";
            return x._data(e, n) || x._data(e, n, {
                empty: x.Callbacks("once memory").add(function() {
                    x._removeData(e, t + "queue"), x._removeData(e, n);
                })
            });
        }
    }), x.fn.extend({
        queue: function(e, n) {
            var r = 2;
            return "string" != typeof e && (n = e, e = "fx", r--), r > arguments.length ? x.queue(this[0], e) : n === t ? this : this.each(function() {
                var t = x.queue(this, e, n);
                x._queueHooks(this, e), "fx" === e && "inprogress" !== t[0] && x.dequeue(this, e);
            });
        },
        dequeue: function(e) {
            return this.each(function() {
                x.dequeue(this, e);
            });
        },
        delay: function(e, t) {
            return e = x.fx ? x.fx.speeds[e] || e : e, t = t || "fx", this.queue(t, function(t, n) {
                var r = setTimeout(t, e);
                n.stop = function() {
                    clearTimeout(r);
                };
            });
        },
        clearQueue: function(e) {
            return this.queue(e || "fx", []);
        },
        promise: function(e, n) {
            var r, i = 1, o = x.Deferred(), a = this, s = this.length, l = function() {
                --i || o.resolveWith(a, [ a ]);
            };
            "string" != typeof e && (n = e, e = t), e = e || "fx";
            while (s--) r = x._data(a[s], e + "queueHooks"), r && r.empty && (i++, r.empty.add(l));
            return l(), o.promise(n);
        }
    });
    var z, X, U = /[\t\r\n\f]/g, V = /\r/g, Y = /^(?:input|select|textarea|button|object)$/i, J = /^(?:a|area)$/i, G = /^(?:checked|selected)$/i, Q = x.support.getSetAttribute, K = x.support.input;
    x.fn.extend({
        attr: function(e, t) {
            return x.access(this, x.attr, e, t, arguments.length > 1);
        },
        removeAttr: function(e) {
            return this.each(function() {
                x.removeAttr(this, e);
            });
        },
        prop: function(e, t) {
            return x.access(this, x.prop, e, t, arguments.length > 1);
        },
        removeProp: function(e) {
            return e = x.propFix[e] || e, this.each(function() {
                try {
                    this[e] = t, delete this[e];
                } catch (n) {}
            });
        },
        addClass: function(e) {
            var t, n, r, i, o, a = 0, s = this.length, l = "string" == typeof e && e;
            if (x.isFunction(e)) return this.each(function(t) {
                x(this).addClass(e.call(this, t, this.className));
            });
            if (l) for (t = (e || "").match(T) || []; s > a; a++) if (n = this[a], r = 1 === n.nodeType && (n.className ? (" " + n.className + " ").replace(U, " ") : " ")) {
                o = 0;
                while (i = t[o++]) 0 > r.indexOf(" " + i + " ") && (r += i + " ");
                n.className = x.trim(r);
            }
            return this;
        },
        removeClass: function(e) {
            var t, n, r, i, o, a = 0, s = this.length, l = 0 === arguments.length || "string" == typeof e && e;
            if (x.isFunction(e)) return this.each(function(t) {
                x(this).removeClass(e.call(this, t, this.className));
            });
            if (l) for (t = (e || "").match(T) || []; s > a; a++) if (n = this[a], r = 1 === n.nodeType && (n.className ? (" " + n.className + " ").replace(U, " ") : "")) {
                o = 0;
                while (i = t[o++]) while (r.indexOf(" " + i + " ") >= 0) r = r.replace(" " + i + " ", " ");
                n.className = e ? x.trim(r) : "";
            }
            return this;
        },
        toggleClass: function(e, t) {
            var n = typeof e;
            return "boolean" == typeof t && "string" === n ? t ? this.addClass(e) : this.removeClass(e) : x.isFunction(e) ? this.each(function(n) {
                x(this).toggleClass(e.call(this, n, this.className, t), t);
            }) : this.each(function() {
                if ("string" === n) {
                    var t, r = 0, o = x(this), a = e.match(T) || [];
                    while (t = a[r++]) o.hasClass(t) ? o.removeClass(t) : o.addClass(t);
                } else (n === i || "boolean" === n) && (this.className && x._data(this, "__className__", this.className), 
                this.className = this.className || e === !1 ? "" : x._data(this, "__className__") || "");
            });
        },
        hasClass: function(e) {
            var t = " " + e + " ", n = 0, r = this.length;
            for (;r > n; n++) if (1 === this[n].nodeType && (" " + this[n].className + " ").replace(U, " ").indexOf(t) >= 0) return !0;
            return !1;
        },
        val: function(e) {
            var n, r, i, o = this[0];
            {
                if (arguments.length) return i = x.isFunction(e), this.each(function(n) {
                    var o;
                    1 === this.nodeType && (o = i ? e.call(this, n, x(this).val()) : e, null == o ? o = "" : "number" == typeof o ? o += "" : x.isArray(o) && (o = x.map(o, function(e) {
                        return null == e ? "" : e + "";
                    })), r = x.valHooks[this.type] || x.valHooks[this.nodeName.toLowerCase()], r && "set" in r && r.set(this, o, "value") !== t || (this.value = o));
                });
                if (o) return r = x.valHooks[o.type] || x.valHooks[o.nodeName.toLowerCase()], r && "get" in r && (n = r.get(o, "value")) !== t ? n : (n = o.value, 
                "string" == typeof n ? n.replace(V, "") : null == n ? "" : n);
            }
        }
    }), x.extend({
        valHooks: {
            option: {
                get: function(e) {
                    var t = x.find.attr(e, "value");
                    return null != t ? t : e.text;
                }
            },
            select: {
                get: function(e) {
                    var t, n, r = e.options, i = e.selectedIndex, o = "select-one" === e.type || 0 > i, a = o ? null : [], s = o ? i + 1 : r.length, l = 0 > i ? s : o ? i : 0;
                    for (;s > l; l++) if (n = r[l], !(!n.selected && l !== i || (x.support.optDisabled ? n.disabled : null !== n.getAttribute("disabled")) || n.parentNode.disabled && x.nodeName(n.parentNode, "optgroup"))) {
                        if (t = x(n).val(), o) return t;
                        a.push(t);
                    }
                    return a;
                },
                set: function(e, t) {
                    var n, r, i = e.options, o = x.makeArray(t), a = i.length;
                    while (a--) r = i[a], (r.selected = x.inArray(x(r).val(), o) >= 0) && (n = !0);
                    return n || (e.selectedIndex = -1), o;
                }
            }
        },
        attr: function(e, n, r) {
            var o, a, s = e.nodeType;
            if (e && 3 !== s && 8 !== s && 2 !== s) return typeof e.getAttribute === i ? x.prop(e, n, r) : (1 === s && x.isXMLDoc(e) || (n = n.toLowerCase(), 
            o = x.attrHooks[n] || (x.expr.match.bool.test(n) ? X : z)), r === t ? o && "get" in o && null !== (a = o.get(e, n)) ? a : (a = x.find.attr(e, n), 
            null == a ? t : a) : null !== r ? o && "set" in o && (a = o.set(e, r, n)) !== t ? a : (e.setAttribute(n, r + ""), 
            r) : (x.removeAttr(e, n), t));
        },
        removeAttr: function(e, t) {
            var n, r, i = 0, o = t && t.match(T);
            if (o && 1 === e.nodeType) while (n = o[i++]) r = x.propFix[n] || n, x.expr.match.bool.test(n) ? K && Q || !G.test(n) ? e[r] = !1 : e[x.camelCase("default-" + n)] = e[r] = !1 : x.attr(e, n, ""), 
            e.removeAttribute(Q ? n : r);
        },
        attrHooks: {
            type: {
                set: function(e, t) {
                    if (!x.support.radioValue && "radio" === t && x.nodeName(e, "input")) {
                        var n = e.value;
                        return e.setAttribute("type", t), n && (e.value = n), t;
                    }
                }
            }
        },
        propFix: {
            "for": "htmlFor",
            "class": "className"
        },
        prop: function(e, n, r) {
            var i, o, a, s = e.nodeType;
            if (e && 3 !== s && 8 !== s && 2 !== s) return a = 1 !== s || !x.isXMLDoc(e), a && (n = x.propFix[n] || n, 
            o = x.propHooks[n]), r !== t ? o && "set" in o && (i = o.set(e, r, n)) !== t ? i : e[n] = r : o && "get" in o && null !== (i = o.get(e, n)) ? i : e[n];
        },
        propHooks: {
            tabIndex: {
                get: function(e) {
                    var t = x.find.attr(e, "tabindex");
                    return t ? parseInt(t, 10) : Y.test(e.nodeName) || J.test(e.nodeName) && e.href ? 0 : -1;
                }
            }
        }
    }), X = {
        set: function(e, t, n) {
            return t === !1 ? x.removeAttr(e, n) : K && Q || !G.test(n) ? e.setAttribute(!Q && x.propFix[n] || n, n) : e[x.camelCase("default-" + n)] = e[n] = !0, 
            n;
        }
    }, x.each(x.expr.match.bool.source.match(/\w+/g), function(e, n) {
        var r = x.expr.attrHandle[n] || x.find.attr;
        x.expr.attrHandle[n] = K && Q || !G.test(n) ? function(e, n, i) {
            var o = x.expr.attrHandle[n], a = i ? t : (x.expr.attrHandle[n] = t) != r(e, n, i) ? n.toLowerCase() : null;
            return x.expr.attrHandle[n] = o, a;
        } : function(e, n, r) {
            return r ? t : e[x.camelCase("default-" + n)] ? n.toLowerCase() : null;
        };
    }), K && Q || (x.attrHooks.value = {
        set: function(e, n, r) {
            return x.nodeName(e, "input") ? (e.defaultValue = n, t) : z && z.set(e, n, r);
        }
    }), Q || (z = {
        set: function(e, n, r) {
            var i = e.getAttributeNode(r);
            return i || e.setAttributeNode(i = e.ownerDocument.createAttribute(r)), i.value = n += "", 
            "value" === r || n === e.getAttribute(r) ? n : t;
        }
    }, x.expr.attrHandle.id = x.expr.attrHandle.name = x.expr.attrHandle.coords = function(e, n, r) {
        var i;
        return r ? t : (i = e.getAttributeNode(n)) && "" !== i.value ? i.value : null;
    }, x.valHooks.button = {
        get: function(e, n) {
            var r = e.getAttributeNode(n);
            return r && r.specified ? r.value : t;
        },
        set: z.set
    }, x.attrHooks.contenteditable = {
        set: function(e, t, n) {
            z.set(e, "" === t ? !1 : t, n);
        }
    }, x.each([ "width", "height" ], function(e, n) {
        x.attrHooks[n] = {
            set: function(e, r) {
                return "" === r ? (e.setAttribute(n, "auto"), r) : t;
            }
        };
    })), x.support.hrefNormalized || x.each([ "href", "src" ], function(e, t) {
        x.propHooks[t] = {
            get: function(e) {
                return e.getAttribute(t, 4);
            }
        };
    }), x.support.style || (x.attrHooks.style = {
        get: function(e) {
            return e.style.cssText || t;
        },
        set: function(e, t) {
            return e.style.cssText = t + "";
        }
    }), x.support.optSelected || (x.propHooks.selected = {
        get: function(e) {
            var t = e.parentNode;
            return t && (t.selectedIndex, t.parentNode && t.parentNode.selectedIndex), null;
        }
    }), x.each([ "tabIndex", "readOnly", "maxLength", "cellSpacing", "cellPadding", "rowSpan", "colSpan", "useMap", "frameBorder", "contentEditable" ], function() {
        x.propFix[this.toLowerCase()] = this;
    }), x.support.enctype || (x.propFix.enctype = "encoding"), x.each([ "radio", "checkbox" ], function() {
        x.valHooks[this] = {
            set: function(e, n) {
                return x.isArray(n) ? e.checked = x.inArray(x(e).val(), n) >= 0 : t;
            }
        }, x.support.checkOn || (x.valHooks[this].get = function(e) {
            return null === e.getAttribute("value") ? "on" : e.value;
        });
    });
    var Z = /^(?:input|select|textarea)$/i, et = /^key/, tt = /^(?:mouse|contextmenu)|click/, nt = /^(?:focusinfocus|focusoutblur)$/, rt = /^([^.]*)(?:\.(.+)|)$/;
    function it() {
        return !0;
    }
    function ot() {
        return !1;
    }
    function at() {
        try {
            return a.activeElement;
        } catch (e) {}
    }
    x.event = {
        global: {},
        add: function(e, n, r, o, a) {
            var s, l, u, c, p, f, d, h, g, m, y, v = x._data(e);
            if (v) {
                r.handler && (c = r, r = c.handler, a = c.selector), r.guid || (r.guid = x.guid++), 
                (l = v.events) || (l = v.events = {}), (f = v.handle) || (f = v.handle = function(e) {
                    return typeof x === i || e && x.event.triggered === e.type ? t : x.event.dispatch.apply(f.elem, arguments);
                }, f.elem = e), n = (n || "").match(T) || [ "" ], u = n.length;
                while (u--) s = rt.exec(n[u]) || [], g = y = s[1], m = (s[2] || "").split(".").sort(), 
                g && (p = x.event.special[g] || {}, g = (a ? p.delegateType : p.bindType) || g, 
                p = x.event.special[g] || {}, d = x.extend({
                    type: g,
                    origType: y,
                    data: o,
                    handler: r,
                    guid: r.guid,
                    selector: a,
                    needsContext: a && x.expr.match.needsContext.test(a),
                    namespace: m.join(".")
                }, c), (h = l[g]) || (h = l[g] = [], h.delegateCount = 0, p.setup && p.setup.call(e, o, m, f) !== !1 || (e.addEventListener ? e.addEventListener(g, f, !1) : e.attachEvent && e.attachEvent("on" + g, f))), 
                p.add && (p.add.call(e, d), d.handler.guid || (d.handler.guid = r.guid)), a ? h.splice(h.delegateCount++, 0, d) : h.push(d), 
                x.event.global[g] = !0);
                e = null;
            }
        },
        remove: function(e, t, n, r, i) {
            var o, a, s, l, u, c, p, f, d, h, g, m = x.hasData(e) && x._data(e);
            if (m && (c = m.events)) {
                t = (t || "").match(T) || [ "" ], u = t.length;
                while (u--) if (s = rt.exec(t[u]) || [], d = g = s[1], h = (s[2] || "").split(".").sort(), 
                d) {
                    p = x.event.special[d] || {}, d = (r ? p.delegateType : p.bindType) || d, f = c[d] || [], 
                    s = s[2] && RegExp("(^|\\.)" + h.join("\\.(?:.*\\.|)") + "(\\.|$)"), l = o = f.length;
                    while (o--) a = f[o], !i && g !== a.origType || n && n.guid !== a.guid || s && !s.test(a.namespace) || r && r !== a.selector && ("**" !== r || !a.selector) || (f.splice(o, 1), 
                    a.selector && f.delegateCount--, p.remove && p.remove.call(e, a));
                    l && !f.length && (p.teardown && p.teardown.call(e, h, m.handle) !== !1 || x.removeEvent(e, d, m.handle), 
                    delete c[d]);
                } else for (d in c) x.event.remove(e, d + t[u], n, r, !0);
                x.isEmptyObject(c) && (delete m.handle, x._removeData(e, "events"));
            }
        },
        trigger: function(n, r, i, o) {
            var s, l, u, c, p, f, d, h = [ i || a ], g = v.call(n, "type") ? n.type : n, m = v.call(n, "namespace") ? n.namespace.split(".") : [];
            if (u = f = i = i || a, 3 !== i.nodeType && 8 !== i.nodeType && !nt.test(g + x.event.triggered) && (g.indexOf(".") >= 0 && (m = g.split("."), 
            g = m.shift(), m.sort()), l = 0 > g.indexOf(":") && "on" + g, n = n[x.expando] ? n : new x.Event(g, "object" == typeof n && n), 
            n.isTrigger = o ? 2 : 3, n.namespace = m.join("."), n.namespace_re = n.namespace ? RegExp("(^|\\.)" + m.join("\\.(?:.*\\.|)") + "(\\.|$)") : null, 
            n.result = t, n.target || (n.target = i), r = null == r ? [ n ] : x.makeArray(r, [ n ]), 
            p = x.event.special[g] || {}, o || !p.trigger || p.trigger.apply(i, r) !== !1)) {
                if (!o && !p.noBubble && !x.isWindow(i)) {
                    for (c = p.delegateType || g, nt.test(c + g) || (u = u.parentNode); u; u = u.parentNode) h.push(u), 
                    f = u;
                    f === (i.ownerDocument || a) && h.push(f.defaultView || f.parentWindow || e);
                }
                d = 0;
                while ((u = h[d++]) && !n.isPropagationStopped()) n.type = d > 1 ? c : p.bindType || g, 
                s = (x._data(u, "events") || {})[n.type] && x._data(u, "handle"), s && s.apply(u, r), 
                s = l && u[l], s && x.acceptData(u) && s.apply && s.apply(u, r) === !1 && n.preventDefault();
                if (n.type = g, !o && !n.isDefaultPrevented() && (!p._default || p._default.apply(h.pop(), r) === !1) && x.acceptData(i) && l && i[g] && !x.isWindow(i)) {
                    f = i[l], f && (i[l] = null), x.event.triggered = g;
                    try {
                        i[g]();
                    } catch (y) {}
                    x.event.triggered = t, f && (i[l] = f);
                }
                return n.result;
            }
        },
        dispatch: function(e) {
            e = x.event.fix(e);
            var n, r, i, o, a, s = [], l = g.call(arguments), u = (x._data(this, "events") || {})[e.type] || [], c = x.event.special[e.type] || {};
            if (l[0] = e, e.delegateTarget = this, !c.preDispatch || c.preDispatch.call(this, e) !== !1) {
                s = x.event.handlers.call(this, e, u), n = 0;
                while ((o = s[n++]) && !e.isPropagationStopped()) {
                    e.currentTarget = o.elem, a = 0;
                    while ((i = o.handlers[a++]) && !e.isImmediatePropagationStopped()) (!e.namespace_re || e.namespace_re.test(i.namespace)) && (e.handleObj = i, 
                    e.data = i.data, r = ((x.event.special[i.origType] || {}).handle || i.handler).apply(o.elem, l), 
                    r !== t && (e.result = r) === !1 && (e.preventDefault(), e.stopPropagation()));
                }
                return c.postDispatch && c.postDispatch.call(this, e), e.result;
            }
        },
        handlers: function(e, n) {
            var r, i, o, a, s = [], l = n.delegateCount, u = e.target;
            if (l && u.nodeType && (!e.button || "click" !== e.type)) for (;u != this; u = u.parentNode || this) if (1 === u.nodeType && (u.disabled !== !0 || "click" !== e.type)) {
                for (o = [], a = 0; l > a; a++) i = n[a], r = i.selector + " ", o[r] === t && (o[r] = i.needsContext ? x(r, this).index(u) >= 0 : x.find(r, this, null, [ u ]).length), 
                o[r] && o.push(i);
                o.length && s.push({
                    elem: u,
                    handlers: o
                });
            }
            return n.length > l && s.push({
                elem: this,
                handlers: n.slice(l)
            }), s;
        },
        fix: function(e) {
            if (e[x.expando]) return e;
            var t, n, r, i = e.type, o = e, s = this.fixHooks[i];
            s || (this.fixHooks[i] = s = tt.test(i) ? this.mouseHooks : et.test(i) ? this.keyHooks : {}), 
            r = s.props ? this.props.concat(s.props) : this.props, e = new x.Event(o), t = r.length;
            while (t--) n = r[t], e[n] = o[n];
            return e.target || (e.target = o.srcElement || a), 3 === e.target.nodeType && (e.target = e.target.parentNode), 
            e.metaKey = !!e.metaKey, s.filter ? s.filter(e, o) : e;
        },
        props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
        fixHooks: {},
        keyHooks: {
            props: "char charCode key keyCode".split(" "),
            filter: function(e, t) {
                return null == e.which && (e.which = null != t.charCode ? t.charCode : t.keyCode), 
                e;
            }
        },
        mouseHooks: {
            props: "button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
            filter: function(e, n) {
                var r, i, o, s = n.button, l = n.fromElement;
                return null == e.pageX && null != n.clientX && (i = e.target.ownerDocument || a, 
                o = i.documentElement, r = i.body, e.pageX = n.clientX + (o && o.scrollLeft || r && r.scrollLeft || 0) - (o && o.clientLeft || r && r.clientLeft || 0), 
                e.pageY = n.clientY + (o && o.scrollTop || r && r.scrollTop || 0) - (o && o.clientTop || r && r.clientTop || 0)), 
                !e.relatedTarget && l && (e.relatedTarget = l === e.target ? n.toElement : l), e.which || s === t || (e.which = 1 & s ? 1 : 2 & s ? 3 : 4 & s ? 2 : 0), 
                e;
            }
        },
        special: {
            load: {
                noBubble: !0
            },
            focus: {
                trigger: function() {
                    if (this !== at() && this.focus) try {
                        return this.focus(), !1;
                    } catch (e) {}
                },
                delegateType: "focusin"
            },
            blur: {
                trigger: function() {
                    return this === at() && this.blur ? (this.blur(), !1) : t;
                },
                delegateType: "focusout"
            },
            click: {
                trigger: function() {
                    return x.nodeName(this, "input") && "checkbox" === this.type && this.click ? (this.click(), 
                    !1) : t;
                },
                _default: function(e) {
                    return x.nodeName(e.target, "a");
                }
            },
            beforeunload: {
                postDispatch: function(e) {
                    e.result !== t && (e.originalEvent.returnValue = e.result);
                }
            }
        },
        simulate: function(e, t, n, r) {
            var i = x.extend(new x.Event(), n, {
                type: e,
                isSimulated: !0,
                originalEvent: {}
            });
            r ? x.event.trigger(i, null, t) : x.event.dispatch.call(t, i), i.isDefaultPrevented() && n.preventDefault();
        }
    }, x.removeEvent = a.removeEventListener ? function(e, t, n) {
        e.removeEventListener && e.removeEventListener(t, n, !1);
    } : function(e, t, n) {
        var r = "on" + t;
        e.detachEvent && (typeof e[r] === i && (e[r] = null), e.detachEvent(r, n));
    }, x.Event = function(e, n) {
        return this instanceof x.Event ? (e && e.type ? (this.originalEvent = e, this.type = e.type, 
        this.isDefaultPrevented = e.defaultPrevented || e.returnValue === !1 || e.getPreventDefault && e.getPreventDefault() ? it : ot) : this.type = e, 
        n && x.extend(this, n), this.timeStamp = e && e.timeStamp || x.now(), this[x.expando] = !0, 
        t) : new x.Event(e, n);
    }, x.Event.prototype = {
        isDefaultPrevented: ot,
        isPropagationStopped: ot,
        isImmediatePropagationStopped: ot,
        preventDefault: function() {
            var e = this.originalEvent;
            this.isDefaultPrevented = it, e && (e.preventDefault ? e.preventDefault() : e.returnValue = !1);
        },
        stopPropagation: function() {
            var e = this.originalEvent;
            this.isPropagationStopped = it, e && (e.stopPropagation && e.stopPropagation(), 
            e.cancelBubble = !0);
        },
        stopImmediatePropagation: function() {
            this.isImmediatePropagationStopped = it, this.stopPropagation();
        }
    }, x.each({
        mouseenter: "mouseover",
        mouseleave: "mouseout"
    }, function(e, t) {
        x.event.special[e] = {
            delegateType: t,
            bindType: t,
            handle: function(e) {
                var n, r = this, i = e.relatedTarget, o = e.handleObj;
                return (!i || i !== r && !x.contains(r, i)) && (e.type = o.origType, n = o.handler.apply(this, arguments), 
                e.type = t), n;
            }
        };
    }), x.support.submitBubbles || (x.event.special.submit = {
        setup: function() {
            return x.nodeName(this, "form") ? !1 : (x.event.add(this, "click._submit keypress._submit", function(e) {
                var n = e.target, r = x.nodeName(n, "input") || x.nodeName(n, "button") ? n.form : t;
                r && !x._data(r, "submitBubbles") && (x.event.add(r, "submit._submit", function(e) {
                    e._submit_bubble = !0;
                }), x._data(r, "submitBubbles", !0));
            }), t);
        },
        postDispatch: function(e) {
            e._submit_bubble && (delete e._submit_bubble, this.parentNode && !e.isTrigger && x.event.simulate("submit", this.parentNode, e, !0));
        },
        teardown: function() {
            return x.nodeName(this, "form") ? !1 : (x.event.remove(this, "._submit"), t);
        }
    }), x.support.changeBubbles || (x.event.special.change = {
        setup: function() {
            return Z.test(this.nodeName) ? (("checkbox" === this.type || "radio" === this.type) && (x.event.add(this, "propertychange._change", function(e) {
                "checked" === e.originalEvent.propertyName && (this._just_changed = !0);
            }), x.event.add(this, "click._change", function(e) {
                this._just_changed && !e.isTrigger && (this._just_changed = !1), x.event.simulate("change", this, e, !0);
            })), !1) : (x.event.add(this, "beforeactivate._change", function(e) {
                var t = e.target;
                Z.test(t.nodeName) && !x._data(t, "changeBubbles") && (x.event.add(t, "change._change", function(e) {
                    !this.parentNode || e.isSimulated || e.isTrigger || x.event.simulate("change", this.parentNode, e, !0);
                }), x._data(t, "changeBubbles", !0));
            }), t);
        },
        handle: function(e) {
            var n = e.target;
            return this !== n || e.isSimulated || e.isTrigger || "radio" !== n.type && "checkbox" !== n.type ? e.handleObj.handler.apply(this, arguments) : t;
        },
        teardown: function() {
            return x.event.remove(this, "._change"), !Z.test(this.nodeName);
        }
    }), x.support.focusinBubbles || x.each({
        focus: "focusin",
        blur: "focusout"
    }, function(e, t) {
        var n = 0, r = function(e) {
            x.event.simulate(t, e.target, x.event.fix(e), !0);
        };
        x.event.special[t] = {
            setup: function() {
                0 === n++ && a.addEventListener(e, r, !0);
            },
            teardown: function() {
                0 === --n && a.removeEventListener(e, r, !0);
            }
        };
    }), x.fn.extend({
        on: function(e, n, r, i, o) {
            var a, s;
            if ("object" == typeof e) {
                "string" != typeof n && (r = r || n, n = t);
                for (a in e) this.on(a, n, r, e[a], o);
                return this;
            }
            if (null == r && null == i ? (i = n, r = n = t) : null == i && ("string" == typeof n ? (i = r, 
            r = t) : (i = r, r = n, n = t)), i === !1) i = ot; else if (!i) return this;
            return 1 === o && (s = i, i = function(e) {
                return x().off(e), s.apply(this, arguments);
            }, i.guid = s.guid || (s.guid = x.guid++)), this.each(function() {
                x.event.add(this, e, i, r, n);
            });
        },
        one: function(e, t, n, r) {
            return this.on(e, t, n, r, 1);
        },
        off: function(e, n, r) {
            var i, o;
            if (e && e.preventDefault && e.handleObj) return i = e.handleObj, x(e.delegateTarget).off(i.namespace ? i.origType + "." + i.namespace : i.origType, i.selector, i.handler), 
            this;
            if ("object" == typeof e) {
                for (o in e) this.off(o, n, e[o]);
                return this;
            }
            return (n === !1 || "function" == typeof n) && (r = n, n = t), r === !1 && (r = ot), 
            this.each(function() {
                x.event.remove(this, e, r, n);
            });
        },
        trigger: function(e, t) {
            return this.each(function() {
                x.event.trigger(e, t, this);
            });
        },
        triggerHandler: function(e, n) {
            var r = this[0];
            return r ? x.event.trigger(e, n, r, !0) : t;
        }
    });
    var st = /^.[^:#\[\.,]*$/, lt = /^(?:parents|prev(?:Until|All))/, ut = x.expr.match.needsContext, ct = {
        children: !0,
        contents: !0,
        next: !0,
        prev: !0
    };
    x.fn.extend({
        find: function(e) {
            var t, n = [], r = this, i = r.length;
            if ("string" != typeof e) return this.pushStack(x(e).filter(function() {
                for (t = 0; i > t; t++) if (x.contains(r[t], this)) return !0;
            }));
            for (t = 0; i > t; t++) x.find(e, r[t], n);
            return n = this.pushStack(i > 1 ? x.unique(n) : n), n.selector = this.selector ? this.selector + " " + e : e, 
            n;
        },
        has: function(e) {
            var t, n = x(e, this), r = n.length;
            return this.filter(function() {
                for (t = 0; r > t; t++) if (x.contains(this, n[t])) return !0;
            });
        },
        not: function(e) {
            return this.pushStack(ft(this, e || [], !0));
        },
        filter: function(e) {
            return this.pushStack(ft(this, e || [], !1));
        },
        is: function(e) {
            return !!ft(this, "string" == typeof e && ut.test(e) ? x(e) : e || [], !1).length;
        },
        closest: function(e, t) {
            var n, r = 0, i = this.length, o = [], a = ut.test(e) || "string" != typeof e ? x(e, t || this.context) : 0;
            for (;i > r; r++) for (n = this[r]; n && n !== t; n = n.parentNode) if (11 > n.nodeType && (a ? a.index(n) > -1 : 1 === n.nodeType && x.find.matchesSelector(n, e))) {
                n = o.push(n);
                break;
            }
            return this.pushStack(o.length > 1 ? x.unique(o) : o);
        },
        index: function(e) {
            return e ? "string" == typeof e ? x.inArray(this[0], x(e)) : x.inArray(e.jquery ? e[0] : e, this) : this[0] && this[0].parentNode ? this.first().prevAll().length : -1;
        },
        add: function(e, t) {
            var n = "string" == typeof e ? x(e, t) : x.makeArray(e && e.nodeType ? [ e ] : e), r = x.merge(this.get(), n);
            return this.pushStack(x.unique(r));
        },
        addBack: function(e) {
            return this.add(null == e ? this.prevObject : this.prevObject.filter(e));
        }
    });
    function pt(e, t) {
        do e = e[t]; while (e && 1 !== e.nodeType);
        return e;
    }
    x.each({
        parent: function(e) {
            var t = e.parentNode;
            return t && 11 !== t.nodeType ? t : null;
        },
        parents: function(e) {
            return x.dir(e, "parentNode");
        },
        parentsUntil: function(e, t, n) {
            return x.dir(e, "parentNode", n);
        },
        next: function(e) {
            return pt(e, "nextSibling");
        },
        prev: function(e) {
            return pt(e, "previousSibling");
        },
        nextAll: function(e) {
            return x.dir(e, "nextSibling");
        },
        prevAll: function(e) {
            return x.dir(e, "previousSibling");
        },
        nextUntil: function(e, t, n) {
            return x.dir(e, "nextSibling", n);
        },
        prevUntil: function(e, t, n) {
            return x.dir(e, "previousSibling", n);
        },
        siblings: function(e) {
            return x.sibling((e.parentNode || {}).firstChild, e);
        },
        children: function(e) {
            return x.sibling(e.firstChild);
        },
        contents: function(e) {
            return x.nodeName(e, "iframe") ? e.contentDocument || e.contentWindow.document : x.merge([], e.childNodes);
        }
    }, function(e, t) {
        x.fn[e] = function(n, r) {
            var i = x.map(this, t, n);
            return "Until" !== e.slice(-5) && (r = n), r && "string" == typeof r && (i = x.filter(r, i)), 
            this.length > 1 && (ct[e] || (i = x.unique(i)), lt.test(e) && (i = i.reverse())), 
            this.pushStack(i);
        };
    }), x.extend({
        filter: function(e, t, n) {
            var r = t[0];
            return n && (e = ":not(" + e + ")"), 1 === t.length && 1 === r.nodeType ? x.find.matchesSelector(r, e) ? [ r ] : [] : x.find.matches(e, x.grep(t, function(e) {
                return 1 === e.nodeType;
            }));
        },
        dir: function(e, n, r) {
            var i = [], o = e[n];
            while (o && 9 !== o.nodeType && (r === t || 1 !== o.nodeType || !x(o).is(r))) 1 === o.nodeType && i.push(o), 
            o = o[n];
            return i;
        },
        sibling: function(e, t) {
            var n = [];
            for (;e; e = e.nextSibling) 1 === e.nodeType && e !== t && n.push(e);
            return n;
        }
    });
    function ft(e, t, n) {
        if (x.isFunction(t)) return x.grep(e, function(e, r) {
            return !!t.call(e, r, e) !== n;
        });
        if (t.nodeType) return x.grep(e, function(e) {
            return e === t !== n;
        });
        if ("string" == typeof t) {
            if (st.test(t)) return x.filter(t, e, n);
            t = x.filter(t, e);
        }
        return x.grep(e, function(e) {
            return x.inArray(e, t) >= 0 !== n;
        });
    }
    function dt(e) {
        var t = ht.split("|"), n = e.createDocumentFragment();
        if (n.createElement) while (t.length) n.createElement(t.pop());
        return n;
    }
    var ht = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video", gt = / jQuery\d+="(?:null|\d+)"/g, mt = RegExp("<(?:" + ht + ")[\\s/>]", "i"), yt = /^\s+/, vt = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, bt = /<([\w:]+)/, xt = /<tbody/i, wt = /<|&#?\w+;/, Tt = /<(?:script|style|link)/i, Ct = /^(?:checkbox|radio)$/i, Nt = /checked\s*(?:[^=]|=\s*.checked.)/i, kt = /^$|\/(?:java|ecma)script/i, Et = /^true\/(.*)/, St = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g, At = {
        option: [ 1, "<select multiple='multiple'>", "</select>" ],
        legend: [ 1, "<fieldset>", "</fieldset>" ],
        area: [ 1, "<map>", "</map>" ],
        param: [ 1, "<object>", "</object>" ],
        thead: [ 1, "<table>", "</table>" ],
        tr: [ 2, "<table><tbody>", "</tbody></table>" ],
        col: [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ],
        td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
        _default: x.support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X<div>", "</div>" ]
    }, jt = dt(a), Dt = jt.appendChild(a.createElement("div"));
    At.optgroup = At.option, At.tbody = At.tfoot = At.colgroup = At.caption = At.thead, 
    At.th = At.td, x.fn.extend({
        text: function(e) {
            return x.access(this, function(e) {
                return e === t ? x.text(this) : this.empty().append((this[0] && this[0].ownerDocument || a).createTextNode(e));
            }, null, e, arguments.length);
        },
        append: function() {
            return this.domManip(arguments, function(e) {
                if (1 === this.nodeType || 11 === this.nodeType || 9 === this.nodeType) {
                    var t = Lt(this, e);
                    t.appendChild(e);
                }
            });
        },
        prepend: function() {
            return this.domManip(arguments, function(e) {
                if (1 === this.nodeType || 11 === this.nodeType || 9 === this.nodeType) {
                    var t = Lt(this, e);
                    t.insertBefore(e, t.firstChild);
                }
            });
        },
        before: function() {
            return this.domManip(arguments, function(e) {
                this.parentNode && this.parentNode.insertBefore(e, this);
            });
        },
        after: function() {
            return this.domManip(arguments, function(e) {
                this.parentNode && this.parentNode.insertBefore(e, this.nextSibling);
            });
        },
        remove: function(e, t) {
            var n, r = e ? x.filter(e, this) : this, i = 0;
            for (;null != (n = r[i]); i++) t || 1 !== n.nodeType || x.cleanData(Ft(n)), n.parentNode && (t && x.contains(n.ownerDocument, n) && _t(Ft(n, "script")), 
            n.parentNode.removeChild(n));
            return this;
        },
        empty: function() {
            var e, t = 0;
            for (;null != (e = this[t]); t++) {
                1 === e.nodeType && x.cleanData(Ft(e, !1));
                while (e.firstChild) e.removeChild(e.firstChild);
                e.options && x.nodeName(e, "select") && (e.options.length = 0);
            }
            return this;
        },
        clone: function(e, t) {
            return e = null == e ? !1 : e, t = null == t ? e : t, this.map(function() {
                return x.clone(this, e, t);
            });
        },
        html: function(e) {
            return x.access(this, function(e) {
                var n = this[0] || {}, r = 0, i = this.length;
                if (e === t) return 1 === n.nodeType ? n.innerHTML.replace(gt, "") : t;
                if (!("string" != typeof e || Tt.test(e) || !x.support.htmlSerialize && mt.test(e) || !x.support.leadingWhitespace && yt.test(e) || At[(bt.exec(e) || [ "", "" ])[1].toLowerCase()])) {
                    e = e.replace(vt, "<$1></$2>");
                    try {
                        for (;i > r; r++) n = this[r] || {}, 1 === n.nodeType && (x.cleanData(Ft(n, !1)), 
                        n.innerHTML = e);
                        n = 0;
                    } catch (o) {}
                }
                n && this.empty().append(e);
            }, null, e, arguments.length);
        },
        replaceWith: function() {
            var e = x.map(this, function(e) {
                return [ e.nextSibling, e.parentNode ];
            }), t = 0;
            return this.domManip(arguments, function(n) {
                var r = e[t++], i = e[t++];
                i && (r && r.parentNode !== i && (r = this.nextSibling), x(this).remove(), i.insertBefore(n, r));
            }, !0), t ? this : this.remove();
        },
        detach: function(e) {
            return this.remove(e, !0);
        },
        domManip: function(e, t, n) {
            e = d.apply([], e);
            var r, i, o, a, s, l, u = 0, c = this.length, p = this, f = c - 1, h = e[0], g = x.isFunction(h);
            if (g || !(1 >= c || "string" != typeof h || x.support.checkClone) && Nt.test(h)) return this.each(function(r) {
                var i = p.eq(r);
                g && (e[0] = h.call(this, r, i.html())), i.domManip(e, t, n);
            });
            if (c && (l = x.buildFragment(e, this[0].ownerDocument, !1, !n && this), r = l.firstChild, 
            1 === l.childNodes.length && (l = r), r)) {
                for (a = x.map(Ft(l, "script"), Ht), o = a.length; c > u; u++) i = l, u !== f && (i = x.clone(i, !0, !0), 
                o && x.merge(a, Ft(i, "script"))), t.call(this[u], i, u);
                if (o) for (s = a[a.length - 1].ownerDocument, x.map(a, qt), u = 0; o > u; u++) i = a[u], 
                kt.test(i.type || "") && !x._data(i, "globalEval") && x.contains(s, i) && (i.src ? x._evalUrl(i.src) : x.globalEval((i.text || i.textContent || i.innerHTML || "").replace(St, "")));
                l = r = null;
            }
            return this;
        }
    });
    function Lt(e, t) {
        return x.nodeName(e, "table") && x.nodeName(1 === t.nodeType ? t : t.firstChild, "tr") ? e.getElementsByTagName("tbody")[0] || e.appendChild(e.ownerDocument.createElement("tbody")) : e;
    }
    function Ht(e) {
        return e.type = (null !== x.find.attr(e, "type")) + "/" + e.type, e;
    }
    function qt(e) {
        var t = Et.exec(e.type);
        return t ? e.type = t[1] : e.removeAttribute("type"), e;
    }
    function _t(e, t) {
        var n, r = 0;
        for (;null != (n = e[r]); r++) x._data(n, "globalEval", !t || x._data(t[r], "globalEval"));
    }
    function Mt(e, t) {
        if (1 === t.nodeType && x.hasData(e)) {
            var n, r, i, o = x._data(e), a = x._data(t, o), s = o.events;
            if (s) {
                delete a.handle, a.events = {};
                for (n in s) for (r = 0, i = s[n].length; i > r; r++) x.event.add(t, n, s[n][r]);
            }
            a.data && (a.data = x.extend({}, a.data));
        }
    }
    function Ot(e, t) {
        var n, r, i;
        if (1 === t.nodeType) {
            if (n = t.nodeName.toLowerCase(), !x.support.noCloneEvent && t[x.expando]) {
                i = x._data(t);
                for (r in i.events) x.removeEvent(t, r, i.handle);
                t.removeAttribute(x.expando);
            }
            "script" === n && t.text !== e.text ? (Ht(t).text = e.text, qt(t)) : "object" === n ? (t.parentNode && (t.outerHTML = e.outerHTML), 
            x.support.html5Clone && e.innerHTML && !x.trim(t.innerHTML) && (t.innerHTML = e.innerHTML)) : "input" === n && Ct.test(e.type) ? (t.defaultChecked = t.checked = e.checked, 
            t.value !== e.value && (t.value = e.value)) : "option" === n ? t.defaultSelected = t.selected = e.defaultSelected : ("input" === n || "textarea" === n) && (t.defaultValue = e.defaultValue);
        }
    }
    x.each({
        appendTo: "append",
        prependTo: "prepend",
        insertBefore: "before",
        insertAfter: "after",
        replaceAll: "replaceWith"
    }, function(e, t) {
        x.fn[e] = function(e) {
            var n, r = 0, i = [], o = x(e), a = o.length - 1;
            for (;a >= r; r++) n = r === a ? this : this.clone(!0), x(o[r])[t](n), h.apply(i, n.get());
            return this.pushStack(i);
        };
    });
    function Ft(e, n) {
        var r, o, a = 0, s = typeof e.getElementsByTagName !== i ? e.getElementsByTagName(n || "*") : typeof e.querySelectorAll !== i ? e.querySelectorAll(n || "*") : t;
        if (!s) for (s = [], r = e.childNodes || e; null != (o = r[a]); a++) !n || x.nodeName(o, n) ? s.push(o) : x.merge(s, Ft(o, n));
        return n === t || n && x.nodeName(e, n) ? x.merge([ e ], s) : s;
    }
    function Bt(e) {
        Ct.test(e.type) && (e.defaultChecked = e.checked);
    }
    x.extend({
        clone: function(e, t, n) {
            var r, i, o, a, s, l = x.contains(e.ownerDocument, e);
            if (x.support.html5Clone || x.isXMLDoc(e) || !mt.test("<" + e.nodeName + ">") ? o = e.cloneNode(!0) : (Dt.innerHTML = e.outerHTML, 
            Dt.removeChild(o = Dt.firstChild)), !(x.support.noCloneEvent && x.support.noCloneChecked || 1 !== e.nodeType && 11 !== e.nodeType || x.isXMLDoc(e))) for (r = Ft(o), 
            s = Ft(e), a = 0; null != (i = s[a]); ++a) r[a] && Ot(i, r[a]);
            if (t) if (n) for (s = s || Ft(e), r = r || Ft(o), a = 0; null != (i = s[a]); a++) Mt(i, r[a]); else Mt(e, o);
            return r = Ft(o, "script"), r.length > 0 && _t(r, !l && Ft(e, "script")), r = s = i = null, 
            o;
        },
        buildFragment: function(e, t, n, r) {
            var i, o, a, s, l, u, c, p = e.length, f = dt(t), d = [], h = 0;
            for (;p > h; h++) if (o = e[h], o || 0 === o) if ("object" === x.type(o)) x.merge(d, o.nodeType ? [ o ] : o); else if (wt.test(o)) {
                s = s || f.appendChild(t.createElement("div")), l = (bt.exec(o) || [ "", "" ])[1].toLowerCase(), 
                c = At[l] || At._default, s.innerHTML = c[1] + o.replace(vt, "<$1></$2>") + c[2], 
                i = c[0];
                while (i--) s = s.lastChild;
                if (!x.support.leadingWhitespace && yt.test(o) && d.push(t.createTextNode(yt.exec(o)[0])), 
                !x.support.tbody) {
                    o = "table" !== l || xt.test(o) ? "<table>" !== c[1] || xt.test(o) ? 0 : s : s.firstChild, 
                    i = o && o.childNodes.length;
                    while (i--) x.nodeName(u = o.childNodes[i], "tbody") && !u.childNodes.length && o.removeChild(u);
                }
                x.merge(d, s.childNodes), s.textContent = "";
                while (s.firstChild) s.removeChild(s.firstChild);
                s = f.lastChild;
            } else d.push(t.createTextNode(o));
            s && f.removeChild(s), x.support.appendChecked || x.grep(Ft(d, "input"), Bt), h = 0;
            while (o = d[h++]) if ((!r || -1 === x.inArray(o, r)) && (a = x.contains(o.ownerDocument, o), 
            s = Ft(f.appendChild(o), "script"), a && _t(s), n)) {
                i = 0;
                while (o = s[i++]) kt.test(o.type || "") && n.push(o);
            }
            return s = null, f;
        },
        cleanData: function(e, t) {
            var n, r, o, a, s = 0, l = x.expando, u = x.cache, c = x.support.deleteExpando, f = x.event.special;
            for (;null != (n = e[s]); s++) if ((t || x.acceptData(n)) && (o = n[l], a = o && u[o])) {
                if (a.events) for (r in a.events) f[r] ? x.event.remove(n, r) : x.removeEvent(n, r, a.handle);
                u[o] && (delete u[o], c ? delete n[l] : typeof n.removeAttribute !== i ? n.removeAttribute(l) : n[l] = null, 
                p.push(o));
            }
        },
        _evalUrl: function(e) {
            return x.ajax({
                url: e,
                type: "GET",
                dataType: "script",
                async: !1,
                global: !1,
                "throws": !0
            });
        }
    }), x.fn.extend({
        wrapAll: function(e) {
            if (x.isFunction(e)) return this.each(function(t) {
                x(this).wrapAll(e.call(this, t));
            });
            if (this[0]) {
                var t = x(e, this[0].ownerDocument).eq(0).clone(!0);
                this[0].parentNode && t.insertBefore(this[0]), t.map(function() {
                    var e = this;
                    while (e.firstChild && 1 === e.firstChild.nodeType) e = e.firstChild;
                    return e;
                }).append(this);
            }
            return this;
        },
        wrapInner: function(e) {
            return x.isFunction(e) ? this.each(function(t) {
                x(this).wrapInner(e.call(this, t));
            }) : this.each(function() {
                var t = x(this), n = t.contents();
                n.length ? n.wrapAll(e) : t.append(e);
            });
        },
        wrap: function(e) {
            var t = x.isFunction(e);
            return this.each(function(n) {
                x(this).wrapAll(t ? e.call(this, n) : e);
            });
        },
        unwrap: function() {
            return this.parent().each(function() {
                x.nodeName(this, "body") || x(this).replaceWith(this.childNodes);
            }).end();
        }
    });
    var Pt, Rt, Wt, $t = /alpha\([^)]*\)/i, It = /opacity\s*=\s*([^)]*)/, zt = /^(top|right|bottom|left)$/, Xt = /^(none|table(?!-c[ea]).+)/, Ut = /^margin/, Vt = RegExp("^(" + w + ")(.*)$", "i"), Yt = RegExp("^(" + w + ")(?!px)[a-z%]+$", "i"), Jt = RegExp("^([+-])=(" + w + ")", "i"), Gt = {
        BODY: "block"
    }, Qt = {
        position: "absolute",
        visibility: "hidden",
        display: "block"
    }, Kt = {
        letterSpacing: 0,
        fontWeight: 400
    }, Zt = [ "Top", "Right", "Bottom", "Left" ], en = [ "Webkit", "O", "Moz", "ms" ];
    function tn(e, t) {
        if (t in e) return t;
        var n = t.charAt(0).toUpperCase() + t.slice(1), r = t, i = en.length;
        while (i--) if (t = en[i] + n, t in e) return t;
        return r;
    }
    function nn(e, t) {
        return e = t || e, "none" === x.css(e, "display") || !x.contains(e.ownerDocument, e);
    }
    function rn(e, t) {
        var n, r, i, o = [], a = 0, s = e.length;
        for (;s > a; a++) r = e[a], r.style && (o[a] = x._data(r, "olddisplay"), n = r.style.display, 
        t ? (o[a] || "none" !== n || (r.style.display = ""), "" === r.style.display && nn(r) && (o[a] = x._data(r, "olddisplay", ln(r.nodeName)))) : o[a] || (i = nn(r), 
        (n && "none" !== n || !i) && x._data(r, "olddisplay", i ? n : x.css(r, "display"))));
        for (a = 0; s > a; a++) r = e[a], r.style && (t && "none" !== r.style.display && "" !== r.style.display || (r.style.display = t ? o[a] || "" : "none"));
        return e;
    }
    x.fn.extend({
        css: function(e, n) {
            return x.access(this, function(e, n, r) {
                var i, o, a = {}, s = 0;
                if (x.isArray(n)) {
                    for (o = Rt(e), i = n.length; i > s; s++) a[n[s]] = x.css(e, n[s], !1, o);
                    return a;
                }
                return r !== t ? x.style(e, n, r) : x.css(e, n);
            }, e, n, arguments.length > 1);
        },
        show: function() {
            return rn(this, !0);
        },
        hide: function() {
            return rn(this);
        },
        toggle: function(e) {
            return "boolean" == typeof e ? e ? this.show() : this.hide() : this.each(function() {
                nn(this) ? x(this).show() : x(this).hide();
            });
        }
    }), x.extend({
        cssHooks: {
            opacity: {
                get: function(e, t) {
                    if (t) {
                        var n = Wt(e, "opacity");
                        return "" === n ? "1" : n;
                    }
                }
            }
        },
        cssNumber: {
            columnCount: !0,
            fillOpacity: !0,
            fontWeight: !0,
            lineHeight: !0,
            opacity: !0,
            order: !0,
            orphans: !0,
            widows: !0,
            zIndex: !0,
            zoom: !0
        },
        cssProps: {
            "float": x.support.cssFloat ? "cssFloat" : "styleFloat"
        },
        style: function(e, n, r, i) {
            if (e && 3 !== e.nodeType && 8 !== e.nodeType && e.style) {
                var o, a, s, l = x.camelCase(n), u = e.style;
                if (n = x.cssProps[l] || (x.cssProps[l] = tn(u, l)), s = x.cssHooks[n] || x.cssHooks[l], 
                r === t) return s && "get" in s && (o = s.get(e, !1, i)) !== t ? o : u[n];
                if (a = typeof r, "string" === a && (o = Jt.exec(r)) && (r = (o[1] + 1) * o[2] + parseFloat(x.css(e, n)), 
                a = "number"), !(null == r || "number" === a && isNaN(r) || ("number" !== a || x.cssNumber[l] || (r += "px"), 
                x.support.clearCloneStyle || "" !== r || 0 !== n.indexOf("background") || (u[n] = "inherit"), 
                s && "set" in s && (r = s.set(e, r, i)) === t))) try {
                    u[n] = r;
                } catch (c) {}
            }
        },
        css: function(e, n, r, i) {
            var o, a, s, l = x.camelCase(n);
            return n = x.cssProps[l] || (x.cssProps[l] = tn(e.style, l)), s = x.cssHooks[n] || x.cssHooks[l], 
            s && "get" in s && (a = s.get(e, !0, r)), a === t && (a = Wt(e, n, i)), "normal" === a && n in Kt && (a = Kt[n]), 
            "" === r || r ? (o = parseFloat(a), r === !0 || x.isNumeric(o) ? o || 0 : a) : a;
        }
    }), e.getComputedStyle ? (Rt = function(t) {
        return e.getComputedStyle(t, null);
    }, Wt = function(e, n, r) {
        var i, o, a, s = r || Rt(e), l = s ? s.getPropertyValue(n) || s[n] : t, u = e.style;
        return s && ("" !== l || x.contains(e.ownerDocument, e) || (l = x.style(e, n)), 
        Yt.test(l) && Ut.test(n) && (i = u.width, o = u.minWidth, a = u.maxWidth, u.minWidth = u.maxWidth = u.width = l, 
        l = s.width, u.width = i, u.minWidth = o, u.maxWidth = a)), l;
    }) : a.documentElement.currentStyle && (Rt = function(e) {
        return e.currentStyle;
    }, Wt = function(e, n, r) {
        var i, o, a, s = r || Rt(e), l = s ? s[n] : t, u = e.style;
        return null == l && u && u[n] && (l = u[n]), Yt.test(l) && !zt.test(n) && (i = u.left, 
        o = e.runtimeStyle, a = o && o.left, a && (o.left = e.currentStyle.left), u.left = "fontSize" === n ? "1em" : l, 
        l = u.pixelLeft + "px", u.left = i, a && (o.left = a)), "" === l ? "auto" : l;
    });
    function on(e, t, n) {
        var r = Vt.exec(t);
        return r ? Math.max(0, r[1] - (n || 0)) + (r[2] || "px") : t;
    }
    function an(e, t, n, r, i) {
        var o = n === (r ? "border" : "content") ? 4 : "width" === t ? 1 : 0, a = 0;
        for (;4 > o; o += 2) "margin" === n && (a += x.css(e, n + Zt[o], !0, i)), r ? ("content" === n && (a -= x.css(e, "padding" + Zt[o], !0, i)), 
        "margin" !== n && (a -= x.css(e, "border" + Zt[o] + "Width", !0, i))) : (a += x.css(e, "padding" + Zt[o], !0, i), 
        "padding" !== n && (a += x.css(e, "border" + Zt[o] + "Width", !0, i)));
        return a;
    }
    function sn(e, t, n) {
        var r = !0, i = "width" === t ? e.offsetWidth : e.offsetHeight, o = Rt(e), a = x.support.boxSizing && "border-box" === x.css(e, "boxSizing", !1, o);
        if (0 >= i || null == i) {
            if (i = Wt(e, t, o), (0 > i || null == i) && (i = e.style[t]), Yt.test(i)) return i;
            r = a && (x.support.boxSizingReliable || i === e.style[t]), i = parseFloat(i) || 0;
        }
        return i + an(e, t, n || (a ? "border" : "content"), r, o) + "px";
    }
    function ln(e) {
        var t = a, n = Gt[e];
        return n || (n = un(e, t), "none" !== n && n || (Pt = (Pt || x("<iframe frameborder='0' width='0' height='0'/>").css("cssText", "display:block !important")).appendTo(t.documentElement), 
        t = (Pt[0].contentWindow || Pt[0].contentDocument).document, t.write("<!doctype html><html><body>"), 
        t.close(), n = un(e, t), Pt.detach()), Gt[e] = n), n;
    }
    function un(e, t) {
        var n = x(t.createElement(e)).appendTo(t.body), r = x.css(n[0], "display");
        return n.remove(), r;
    }
    x.each([ "height", "width" ], function(e, n) {
        x.cssHooks[n] = {
            get: function(e, r, i) {
                return r ? 0 === e.offsetWidth && Xt.test(x.css(e, "display")) ? x.swap(e, Qt, function() {
                    return sn(e, n, i);
                }) : sn(e, n, i) : t;
            },
            set: function(e, t, r) {
                var i = r && Rt(e);
                return on(e, t, r ? an(e, n, r, x.support.boxSizing && "border-box" === x.css(e, "boxSizing", !1, i), i) : 0);
            }
        };
    }), x.support.opacity || (x.cssHooks.opacity = {
        get: function(e, t) {
            return It.test((t && e.currentStyle ? e.currentStyle.filter : e.style.filter) || "") ? .01 * parseFloat(RegExp.$1) + "" : t ? "1" : "";
        },
        set: function(e, t) {
            var n = e.style, r = e.currentStyle, i = x.isNumeric(t) ? "alpha(opacity=" + 100 * t + ")" : "", o = r && r.filter || n.filter || "";
            n.zoom = 1, (t >= 1 || "" === t) && "" === x.trim(o.replace($t, "")) && n.removeAttribute && (n.removeAttribute("filter"), 
            "" === t || r && !r.filter) || (n.filter = $t.test(o) ? o.replace($t, i) : o + " " + i);
        }
    }), x(function() {
        x.support.reliableMarginRight || (x.cssHooks.marginRight = {
            get: function(e, n) {
                return n ? x.swap(e, {
                    display: "inline-block"
                }, Wt, [ e, "marginRight" ]) : t;
            }
        }), !x.support.pixelPosition && x.fn.position && x.each([ "top", "left" ], function(e, n) {
            x.cssHooks[n] = {
                get: function(e, r) {
                    return r ? (r = Wt(e, n), Yt.test(r) ? x(e).position()[n] + "px" : r) : t;
                }
            };
        });
    }), x.expr && x.expr.filters && (x.expr.filters.hidden = function(e) {
        return 0 >= e.offsetWidth && 0 >= e.offsetHeight || !x.support.reliableHiddenOffsets && "none" === (e.style && e.style.display || x.css(e, "display"));
    }, x.expr.filters.visible = function(e) {
        return !x.expr.filters.hidden(e);
    }), x.each({
        margin: "",
        padding: "",
        border: "Width"
    }, function(e, t) {
        x.cssHooks[e + t] = {
            expand: function(n) {
                var r = 0, i = {}, o = "string" == typeof n ? n.split(" ") : [ n ];
                for (;4 > r; r++) i[e + Zt[r] + t] = o[r] || o[r - 2] || o[0];
                return i;
            }
        }, Ut.test(e) || (x.cssHooks[e + t].set = on);
    });
    var cn = /%20/g, pn = /\[\]$/, fn = /\r?\n/g, dn = /^(?:submit|button|image|reset|file)$/i, hn = /^(?:input|select|textarea|keygen)/i;
    x.fn.extend({
        serialize: function() {
            return x.param(this.serializeArray());
        },
        serializeArray: function() {
            return this.map(function() {
                var e = x.prop(this, "elements");
                return e ? x.makeArray(e) : this;
            }).filter(function() {
                var e = this.type;
                return this.name && !x(this).is(":disabled") && hn.test(this.nodeName) && !dn.test(e) && (this.checked || !Ct.test(e));
            }).map(function(e, t) {
                var n = x(this).val();
                return null == n ? null : x.isArray(n) ? x.map(n, function(e) {
                    return {
                        name: t.name,
                        value: e.replace(fn, "\r\n")
                    };
                }) : {
                    name: t.name,
                    value: n.replace(fn, "\r\n")
                };
            }).get();
        }
    }), x.param = function(e, n) {
        var r, i = [], o = function(e, t) {
            t = x.isFunction(t) ? t() : null == t ? "" : t, i[i.length] = encodeURIComponent(e) + "=" + encodeURIComponent(t);
        };
        if (n === t && (n = x.ajaxSettings && x.ajaxSettings.traditional), x.isArray(e) || e.jquery && !x.isPlainObject(e)) x.each(e, function() {
            o(this.name, this.value);
        }); else for (r in e) gn(r, e[r], n, o);
        return i.join("&").replace(cn, "+");
    };
    function gn(e, t, n, r) {
        var i;
        if (x.isArray(t)) x.each(t, function(t, i) {
            n || pn.test(e) ? r(e, i) : gn(e + "[" + ("object" == typeof i ? t : "") + "]", i, n, r);
        }); else if (n || "object" !== x.type(t)) r(e, t); else for (i in t) gn(e + "[" + i + "]", t[i], n, r);
    }
    x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "), function(e, t) {
        x.fn[t] = function(e, n) {
            return arguments.length > 0 ? this.on(t, null, e, n) : this.trigger(t);
        };
    }), x.fn.extend({
        hover: function(e, t) {
            return this.mouseenter(e).mouseleave(t || e);
        },
        bind: function(e, t, n) {
            return this.on(e, null, t, n);
        },
        unbind: function(e, t) {
            return this.off(e, null, t);
        },
        delegate: function(e, t, n, r) {
            return this.on(t, e, n, r);
        },
        undelegate: function(e, t, n) {
            return 1 === arguments.length ? this.off(e, "**") : this.off(t, e || "**", n);
        }
    });
    var mn, yn, vn = x.now(), bn = /\?/, xn = /#.*$/, wn = /([?&])_=[^&]*/, Tn = /^(.*?):[ \t]*([^\r\n]*)\r?$/gm, Cn = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, Nn = /^(?:GET|HEAD)$/, kn = /^\/\//, En = /^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/, Sn = x.fn.load, An = {}, jn = {}, Dn = "*/".concat("*");
    try {
        yn = o.href;
    } catch (Ln) {
        yn = a.createElement("a"), yn.href = "", yn = yn.href;
    }
    mn = En.exec(yn.toLowerCase()) || [];
    function Hn(e) {
        return function(t, n) {
            "string" != typeof t && (n = t, t = "*");
            var r, i = 0, o = t.toLowerCase().match(T) || [];
            if (x.isFunction(n)) while (r = o[i++]) "+" === r[0] ? (r = r.slice(1) || "*", (e[r] = e[r] || []).unshift(n)) : (e[r] = e[r] || []).push(n);
        };
    }
    function qn(e, n, r, i) {
        var o = {}, a = e === jn;
        function s(l) {
            var u;
            return o[l] = !0, x.each(e[l] || [], function(e, l) {
                var c = l(n, r, i);
                return "string" != typeof c || a || o[c] ? a ? !(u = c) : t : (n.dataTypes.unshift(c), 
                s(c), !1);
            }), u;
        }
        return s(n.dataTypes[0]) || !o["*"] && s("*");
    }
    function _n(e, n) {
        var r, i, o = x.ajaxSettings.flatOptions || {};
        for (i in n) n[i] !== t && ((o[i] ? e : r || (r = {}))[i] = n[i]);
        return r && x.extend(!0, e, r), e;
    }
    x.fn.load = function(e, n, r) {
        if ("string" != typeof e && Sn) return Sn.apply(this, arguments);
        var i, o, a, s = this, l = e.indexOf(" ");
        return l >= 0 && (i = e.slice(l, e.length), e = e.slice(0, l)), x.isFunction(n) ? (r = n, 
        n = t) : n && "object" == typeof n && (a = "POST"), s.length > 0 && x.ajax({
            url: e,
            type: a,
            dataType: "html",
            data: n
        }).done(function(e) {
            o = arguments, s.html(i ? x("<div>").append(x.parseHTML(e)).find(i) : e);
        }).complete(r && function(e, t) {
            s.each(r, o || [ e.responseText, t, e ]);
        }), this;
    }, x.each([ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function(e, t) {
        x.fn[t] = function(e) {
            return this.on(t, e);
        };
    }), x.extend({
        active: 0,
        lastModified: {},
        etag: {},
        ajaxSettings: {
            url: yn,
            type: "GET",
            isLocal: Cn.test(mn[1]),
            global: !0,
            processData: !0,
            async: !0,
            contentType: "application/x-www-form-urlencoded; charset=UTF-8",
            accepts: {
                "*": Dn,
                text: "text/plain",
                html: "text/html",
                xml: "application/xml, text/xml",
                json: "application/json, text/javascript"
            },
            contents: {
                xml: /xml/,
                html: /html/,
                json: /json/
            },
            responseFields: {
                xml: "responseXML",
                text: "responseText",
                json: "responseJSON"
            },
            converters: {
                "* text": String,
                "text html": !0,
                "text json": x.parseJSON,
                "text xml": x.parseXML
            },
            flatOptions: {
                url: !0,
                context: !0
            }
        },
        ajaxSetup: function(e, t) {
            return t ? _n(_n(e, x.ajaxSettings), t) : _n(x.ajaxSettings, e);
        },
        ajaxPrefilter: Hn(An),
        ajaxTransport: Hn(jn),
        ajax: function(e, n) {
            "object" == typeof e && (n = e, e = t), n = n || {};
            var r, i, o, a, s, l, u, c, p = x.ajaxSetup({}, n), f = p.context || p, d = p.context && (f.nodeType || f.jquery) ? x(f) : x.event, h = x.Deferred(), g = x.Callbacks("once memory"), m = p.statusCode || {}, y = {}, v = {}, b = 0, w = "canceled", C = {
                readyState: 0,
                getResponseHeader: function(e) {
                    var t;
                    if (2 === b) {
                        if (!c) {
                            c = {};
                            while (t = Tn.exec(a)) c[t[1].toLowerCase()] = t[2];
                        }
                        t = c[e.toLowerCase()];
                    }
                    return null == t ? null : t;
                },
                getAllResponseHeaders: function() {
                    return 2 === b ? a : null;
                },
                setRequestHeader: function(e, t) {
                    var n = e.toLowerCase();
                    return b || (e = v[n] = v[n] || e, y[e] = t), this;
                },
                overrideMimeType: function(e) {
                    return b || (p.mimeType = e), this;
                },
                statusCode: function(e) {
                    var t;
                    if (e) if (2 > b) for (t in e) m[t] = [ m[t], e[t] ]; else C.always(e[C.status]);
                    return this;
                },
                abort: function(e) {
                    var t = e || w;
                    return u && u.abort(t), k(0, t), this;
                }
            };
            if (h.promise(C).complete = g.add, C.success = C.done, C.error = C.fail, p.url = ((e || p.url || yn) + "").replace(xn, "").replace(kn, mn[1] + "//"), 
            p.type = n.method || n.type || p.method || p.type, p.dataTypes = x.trim(p.dataType || "*").toLowerCase().match(T) || [ "" ], 
            null == p.crossDomain && (r = En.exec(p.url.toLowerCase()), p.crossDomain = !(!r || r[1] === mn[1] && r[2] === mn[2] && (r[3] || ("http:" === r[1] ? "80" : "443")) === (mn[3] || ("http:" === mn[1] ? "80" : "443")))), 
            p.data && p.processData && "string" != typeof p.data && (p.data = x.param(p.data, p.traditional)), 
            qn(An, p, n, C), 2 === b) return C;
            l = p.global, l && 0 === x.active++ && x.event.trigger("ajaxStart"), p.type = p.type.toUpperCase(), 
            p.hasContent = !Nn.test(p.type), o = p.url, p.hasContent || (p.data && (o = p.url += (bn.test(o) ? "&" : "?") + p.data, 
            delete p.data), p.cache === !1 && (p.url = wn.test(o) ? o.replace(wn, "$1_=" + vn++) : o + (bn.test(o) ? "&" : "?") + "_=" + vn++)), 
            p.ifModified && (x.lastModified[o] && C.setRequestHeader("If-Modified-Since", x.lastModified[o]), 
            x.etag[o] && C.setRequestHeader("If-None-Match", x.etag[o])), (p.data && p.hasContent && p.contentType !== !1 || n.contentType) && C.setRequestHeader("Content-Type", p.contentType), 
            C.setRequestHeader("Accept", p.dataTypes[0] && p.accepts[p.dataTypes[0]] ? p.accepts[p.dataTypes[0]] + ("*" !== p.dataTypes[0] ? ", " + Dn + "; q=0.01" : "") : p.accepts["*"]);
            for (i in p.headers) C.setRequestHeader(i, p.headers[i]);
            if (p.beforeSend && (p.beforeSend.call(f, C, p) === !1 || 2 === b)) return C.abort();
            w = "abort";
            for (i in {
                success: 1,
                error: 1,
                complete: 1
            }) C[i](p[i]);
            if (u = qn(jn, p, n, C)) {
                C.readyState = 1, l && d.trigger("ajaxSend", [ C, p ]), p.async && p.timeout > 0 && (s = setTimeout(function() {
                    C.abort("timeout");
                }, p.timeout));
                try {
                    b = 1, u.send(y, k);
                } catch (N) {
                    if (!(2 > b)) throw N;
                    k(-1, N);
                }
            } else k(-1, "No Transport");
            function k(e, n, r, i) {
                var c, y, v, w, T, N = n;
                2 !== b && (b = 2, s && clearTimeout(s), u = t, a = i || "", C.readyState = e > 0 ? 4 : 0, 
                c = e >= 200 && 300 > e || 304 === e, r && (w = Mn(p, C, r)), w = On(p, w, C, c), 
                c ? (p.ifModified && (T = C.getResponseHeader("Last-Modified"), T && (x.lastModified[o] = T), 
                T = C.getResponseHeader("etag"), T && (x.etag[o] = T)), 204 === e || "HEAD" === p.type ? N = "nocontent" : 304 === e ? N = "notmodified" : (N = w.state, 
                y = w.data, v = w.error, c = !v)) : (v = N, (e || !N) && (N = "error", 0 > e && (e = 0))), 
                C.status = e, C.statusText = (n || N) + "", c ? h.resolveWith(f, [ y, N, C ]) : h.rejectWith(f, [ C, N, v ]), 
                C.statusCode(m), m = t, l && d.trigger(c ? "ajaxSuccess" : "ajaxError", [ C, p, c ? y : v ]), 
                g.fireWith(f, [ C, N ]), l && (d.trigger("ajaxComplete", [ C, p ]), --x.active || x.event.trigger("ajaxStop")));
            }
            return C;
        },
        getJSON: function(e, t, n) {
            return x.get(e, t, n, "json");
        },
        getScript: function(e, n) {
            return x.get(e, t, n, "script");
        }
    }), x.each([ "get", "post" ], function(e, n) {
        x[n] = function(e, r, i, o) {
            return x.isFunction(r) && (o = o || i, i = r, r = t), x.ajax({
                url: e,
                type: n,
                dataType: o,
                data: r,
                success: i
            });
        };
    });
    function Mn(e, n, r) {
        var i, o, a, s, l = e.contents, u = e.dataTypes;
        while ("*" === u[0]) u.shift(), o === t && (o = e.mimeType || n.getResponseHeader("Content-Type"));
        if (o) for (s in l) if (l[s] && l[s].test(o)) {
            u.unshift(s);
            break;
        }
        if (u[0] in r) a = u[0]; else {
            for (s in r) {
                if (!u[0] || e.converters[s + " " + u[0]]) {
                    a = s;
                    break;
                }
                i || (i = s);
            }
            a = a || i;
        }
        return a ? (a !== u[0] && u.unshift(a), r[a]) : t;
    }
    function On(e, t, n, r) {
        var i, o, a, s, l, u = {}, c = e.dataTypes.slice();
        if (c[1]) for (a in e.converters) u[a.toLowerCase()] = e.converters[a];
        o = c.shift();
        while (o) if (e.responseFields[o] && (n[e.responseFields[o]] = t), !l && r && e.dataFilter && (t = e.dataFilter(t, e.dataType)), 
        l = o, o = c.shift()) if ("*" === o) o = l; else if ("*" !== l && l !== o) {
            if (a = u[l + " " + o] || u["* " + o], !a) for (i in u) if (s = i.split(" "), s[1] === o && (a = u[l + " " + s[0]] || u["* " + s[0]])) {
                a === !0 ? a = u[i] : u[i] !== !0 && (o = s[0], c.unshift(s[1]));
                break;
            }
            if (a !== !0) if (a && e["throws"]) t = a(t); else try {
                t = a(t);
            } catch (p) {
                return {
                    state: "parsererror",
                    error: a ? p : "No conversion from " + l + " to " + o
                };
            }
        }
        return {
            state: "success",
            data: t
        };
    }
    x.ajaxSetup({
        accepts: {
            script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
        },
        contents: {
            script: /(?:java|ecma)script/
        },
        converters: {
            "text script": function(e) {
                return x.globalEval(e), e;
            }
        }
    }), x.ajaxPrefilter("script", function(e) {
        e.cache === t && (e.cache = !1), e.crossDomain && (e.type = "GET", e.global = !1);
    }), x.ajaxTransport("script", function(e) {
        if (e.crossDomain) {
            var n, r = a.head || x("head")[0] || a.documentElement;
            return {
                send: function(t, i) {
                    n = a.createElement("script"), n.async = !0, e.scriptCharset && (n.charset = e.scriptCharset), 
                    n.src = e.url, n.onload = n.onreadystatechange = function(e, t) {
                        (t || !n.readyState || /loaded|complete/.test(n.readyState)) && (n.onload = n.onreadystatechange = null, 
                        n.parentNode && n.parentNode.removeChild(n), n = null, t || i(200, "success"));
                    }, r.insertBefore(n, r.firstChild);
                },
                abort: function() {
                    n && n.onload(t, !0);
                }
            };
        }
    });
    var Fn = [], Bn = /(=)\?(?=&|$)|\?\?/;
    x.ajaxSetup({
        jsonp: "callback",
        jsonpCallback: function() {
            var e = Fn.pop() || x.expando + "_" + vn++;
            return this[e] = !0, e;
        }
    }), x.ajaxPrefilter("json jsonp", function(n, r, i) {
        var o, a, s, l = n.jsonp !== !1 && (Bn.test(n.url) ? "url" : "string" == typeof n.data && !(n.contentType || "").indexOf("application/x-www-form-urlencoded") && Bn.test(n.data) && "data");
        return l || "jsonp" === n.dataTypes[0] ? (o = n.jsonpCallback = x.isFunction(n.jsonpCallback) ? n.jsonpCallback() : n.jsonpCallback, 
        l ? n[l] = n[l].replace(Bn, "$1" + o) : n.jsonp !== !1 && (n.url += (bn.test(n.url) ? "&" : "?") + n.jsonp + "=" + o), 
        n.converters["script json"] = function() {
            return s || x.error(o + " was not called"), s[0];
        }, n.dataTypes[0] = "json", a = e[o], e[o] = function() {
            s = arguments;
        }, i.always(function() {
            e[o] = a, n[o] && (n.jsonpCallback = r.jsonpCallback, Fn.push(o)), s && x.isFunction(a) && a(s[0]), 
            s = a = t;
        }), "script") : t;
    });
    var Pn, Rn, Wn = 0, $n = e.ActiveXObject && function() {
        var e;
        for (e in Pn) Pn[e](t, !0);
    };
    function In() {
        try {
            return new e.XMLHttpRequest();
        } catch (t) {}
    }
    function zn() {
        try {
            return new e.ActiveXObject("Microsoft.XMLHTTP");
        } catch (t) {}
    }
    x.ajaxSettings.xhr = e.ActiveXObject ? function() {
        return !this.isLocal && In() || zn();
    } : In, Rn = x.ajaxSettings.xhr(), x.support.cors = !!Rn && "withCredentials" in Rn, 
    Rn = x.support.ajax = !!Rn, Rn && x.ajaxTransport(function(n) {
        if (!n.crossDomain || x.support.cors) {
            var r;
            return {
                send: function(i, o) {
                    var a, s, l = n.xhr();
                    if (n.username ? l.open(n.type, n.url, n.async, n.username, n.password) : l.open(n.type, n.url, n.async), 
                    n.xhrFields) for (s in n.xhrFields) l[s] = n.xhrFields[s];
                    n.mimeType && l.overrideMimeType && l.overrideMimeType(n.mimeType), n.crossDomain || i["X-Requested-With"] || (i["X-Requested-With"] = "XMLHttpRequest");
                    try {
                        for (s in i) l.setRequestHeader(s, i[s]);
                    } catch (u) {}
                    l.send(n.hasContent && n.data || null), r = function(e, i) {
                        var s, u, c, p;
                        try {
                            if (r && (i || 4 === l.readyState)) if (r = t, a && (l.onreadystatechange = x.noop, 
                            $n && delete Pn[a]), i) 4 !== l.readyState && l.abort(); else {
                                p = {}, s = l.status, u = l.getAllResponseHeaders(), "string" == typeof l.responseText && (p.text = l.responseText);
                                try {
                                    c = l.statusText;
                                } catch (f) {
                                    c = "";
                                }
                                s || !n.isLocal || n.crossDomain ? 1223 === s && (s = 204) : s = p.text ? 200 : 404;
                            }
                        } catch (d) {
                            i || o(-1, d);
                        }
                        p && o(s, c, p, u);
                    }, n.async ? 4 === l.readyState ? setTimeout(r) : (a = ++Wn, $n && (Pn || (Pn = {}, 
                    x(e).unload($n)), Pn[a] = r), l.onreadystatechange = r) : r();
                },
                abort: function() {
                    r && r(t, !0);
                }
            };
        }
    });
    var Xn, Un, Vn = /^(?:toggle|show|hide)$/, Yn = RegExp("^(?:([+-])=|)(" + w + ")([a-z%]*)$", "i"), Jn = /queueHooks$/, Gn = [ nr ], Qn = {
        "*": [ function(e, t) {
            var n = this.createTween(e, t), r = n.cur(), i = Yn.exec(t), o = i && i[3] || (x.cssNumber[e] ? "" : "px"), a = (x.cssNumber[e] || "px" !== o && +r) && Yn.exec(x.css(n.elem, e)), s = 1, l = 20;
            if (a && a[3] !== o) {
                o = o || a[3], i = i || [], a = +r || 1;
                do s = s || ".5", a /= s, x.style(n.elem, e, a + o); while (s !== (s = n.cur() / r) && 1 !== s && --l);
            }
            return i && (a = n.start = +a || +r || 0, n.unit = o, n.end = i[1] ? a + (i[1] + 1) * i[2] : +i[2]), 
            n;
        } ]
    };
    function Kn() {
        return setTimeout(function() {
            Xn = t;
        }), Xn = x.now();
    }
    function Zn(e, t, n) {
        var r, i = (Qn[t] || []).concat(Qn["*"]), o = 0, a = i.length;
        for (;a > o; o++) if (r = i[o].call(n, t, e)) return r;
    }
    function er(e, t, n) {
        var r, i, o = 0, a = Gn.length, s = x.Deferred().always(function() {
            delete l.elem;
        }), l = function() {
            if (i) return !1;
            var t = Xn || Kn(), n = Math.max(0, u.startTime + u.duration - t), r = n / u.duration || 0, o = 1 - r, a = 0, l = u.tweens.length;
            for (;l > a; a++) u.tweens[a].run(o);
            return s.notifyWith(e, [ u, o, n ]), 1 > o && l ? n : (s.resolveWith(e, [ u ]), 
            !1);
        }, u = s.promise({
            elem: e,
            props: x.extend({}, t),
            opts: x.extend(!0, {
                specialEasing: {}
            }, n),
            originalProperties: t,
            originalOptions: n,
            startTime: Xn || Kn(),
            duration: n.duration,
            tweens: [],
            createTween: function(t, n) {
                var r = x.Tween(e, u.opts, t, n, u.opts.specialEasing[t] || u.opts.easing);
                return u.tweens.push(r), r;
            },
            stop: function(t) {
                var n = 0, r = t ? u.tweens.length : 0;
                if (i) return this;
                for (i = !0; r > n; n++) u.tweens[n].run(1);
                return t ? s.resolveWith(e, [ u, t ]) : s.rejectWith(e, [ u, t ]), this;
            }
        }), c = u.props;
        for (tr(c, u.opts.specialEasing); a > o; o++) if (r = Gn[o].call(u, e, c, u.opts)) return r;
        return x.map(c, Zn, u), x.isFunction(u.opts.start) && u.opts.start.call(e, u), x.fx.timer(x.extend(l, {
            elem: e,
            anim: u,
            queue: u.opts.queue
        })), u.progress(u.opts.progress).done(u.opts.done, u.opts.complete).fail(u.opts.fail).always(u.opts.always);
    }
    function tr(e, t) {
        var n, r, i, o, a;
        for (n in e) if (r = x.camelCase(n), i = t[r], o = e[n], x.isArray(o) && (i = o[1], 
        o = e[n] = o[0]), n !== r && (e[r] = o, delete e[n]), a = x.cssHooks[r], a && "expand" in a) {
            o = a.expand(o), delete e[r];
            for (n in o) n in e || (e[n] = o[n], t[n] = i);
        } else t[r] = i;
    }
    x.Animation = x.extend(er, {
        tweener: function(e, t) {
            x.isFunction(e) ? (t = e, e = [ "*" ]) : e = e.split(" ");
            var n, r = 0, i = e.length;
            for (;i > r; r++) n = e[r], Qn[n] = Qn[n] || [], Qn[n].unshift(t);
        },
        prefilter: function(e, t) {
            t ? Gn.unshift(e) : Gn.push(e);
        }
    });
    function nr(e, t, n) {
        var r, i, o, a, s, l, u = this, c = {}, p = e.style, f = e.nodeType && nn(e), d = x._data(e, "fxshow");
        n.queue || (s = x._queueHooks(e, "fx"), null == s.unqueued && (s.unqueued = 0, l = s.empty.fire, 
        s.empty.fire = function() {
            s.unqueued || l();
        }), s.unqueued++, u.always(function() {
            u.always(function() {
                s.unqueued--, x.queue(e, "fx").length || s.empty.fire();
            });
        })), 1 === e.nodeType && ("height" in t || "width" in t) && (n.overflow = [ p.overflow, p.overflowX, p.overflowY ], 
        "inline" === x.css(e, "display") && "none" === x.css(e, "float") && (x.support.inlineBlockNeedsLayout && "inline" !== ln(e.nodeName) ? p.zoom = 1 : p.display = "inline-block")), 
        n.overflow && (p.overflow = "hidden", x.support.shrinkWrapBlocks || u.always(function() {
            p.overflow = n.overflow[0], p.overflowX = n.overflow[1], p.overflowY = n.overflow[2];
        }));
        for (r in t) if (i = t[r], Vn.exec(i)) {
            if (delete t[r], o = o || "toggle" === i, i === (f ? "hide" : "show")) continue;
            c[r] = d && d[r] || x.style(e, r);
        }
        if (!x.isEmptyObject(c)) {
            d ? "hidden" in d && (f = d.hidden) : d = x._data(e, "fxshow", {}), o && (d.hidden = !f), 
            f ? x(e).show() : u.done(function() {
                x(e).hide();
            }), u.done(function() {
                var t;
                x._removeData(e, "fxshow");
                for (t in c) x.style(e, t, c[t]);
            });
            for (r in c) a = Zn(f ? d[r] : 0, r, u), r in d || (d[r] = a.start, f && (a.end = a.start, 
            a.start = "width" === r || "height" === r ? 1 : 0));
        }
    }
    function rr(e, t, n, r, i) {
        return new rr.prototype.init(e, t, n, r, i);
    }
    x.Tween = rr, rr.prototype = {
        constructor: rr,
        init: function(e, t, n, r, i, o) {
            this.elem = e, this.prop = n, this.easing = i || "swing", this.options = t, this.start = this.now = this.cur(), 
            this.end = r, this.unit = o || (x.cssNumber[n] ? "" : "px");
        },
        cur: function() {
            var e = rr.propHooks[this.prop];
            return e && e.get ? e.get(this) : rr.propHooks._default.get(this);
        },
        run: function(e) {
            var t, n = rr.propHooks[this.prop];
            return this.pos = t = this.options.duration ? x.easing[this.easing](e, this.options.duration * e, 0, 1, this.options.duration) : e, 
            this.now = (this.end - this.start) * t + this.start, this.options.step && this.options.step.call(this.elem, this.now, this), 
            n && n.set ? n.set(this) : rr.propHooks._default.set(this), this;
        }
    }, rr.prototype.init.prototype = rr.prototype, rr.propHooks = {
        _default: {
            get: function(e) {
                var t;
                return null == e.elem[e.prop] || e.elem.style && null != e.elem.style[e.prop] ? (t = x.css(e.elem, e.prop, ""), 
                t && "auto" !== t ? t : 0) : e.elem[e.prop];
            },
            set: function(e) {
                x.fx.step[e.prop] ? x.fx.step[e.prop](e) : e.elem.style && (null != e.elem.style[x.cssProps[e.prop]] || x.cssHooks[e.prop]) ? x.style(e.elem, e.prop, e.now + e.unit) : e.elem[e.prop] = e.now;
            }
        }
    }, rr.propHooks.scrollTop = rr.propHooks.scrollLeft = {
        set: function(e) {
            e.elem.nodeType && e.elem.parentNode && (e.elem[e.prop] = e.now);
        }
    }, x.each([ "toggle", "show", "hide" ], function(e, t) {
        var n = x.fn[t];
        x.fn[t] = function(e, r, i) {
            return null == e || "boolean" == typeof e ? n.apply(this, arguments) : this.animate(ir(t, !0), e, r, i);
        };
    }), x.fn.extend({
        fadeTo: function(e, t, n, r) {
            return this.filter(nn).css("opacity", 0).show().end().animate({
                opacity: t
            }, e, n, r);
        },
        animate: function(e, t, n, r) {
            var i = x.isEmptyObject(e), o = x.speed(t, n, r), a = function() {
                var t = er(this, x.extend({}, e), o);
                (i || x._data(this, "finish")) && t.stop(!0);
            };
            return a.finish = a, i || o.queue === !1 ? this.each(a) : this.queue(o.queue, a);
        },
        stop: function(e, n, r) {
            var i = function(e) {
                var t = e.stop;
                delete e.stop, t(r);
            };
            return "string" != typeof e && (r = n, n = e, e = t), n && e !== !1 && this.queue(e || "fx", []), 
            this.each(function() {
                var t = !0, n = null != e && e + "queueHooks", o = x.timers, a = x._data(this);
                if (n) a[n] && a[n].stop && i(a[n]); else for (n in a) a[n] && a[n].stop && Jn.test(n) && i(a[n]);
                for (n = o.length; n--; ) o[n].elem !== this || null != e && o[n].queue !== e || (o[n].anim.stop(r), 
                t = !1, o.splice(n, 1));
                (t || !r) && x.dequeue(this, e);
            });
        },
        finish: function(e) {
            return e !== !1 && (e = e || "fx"), this.each(function() {
                var t, n = x._data(this), r = n[e + "queue"], i = n[e + "queueHooks"], o = x.timers, a = r ? r.length : 0;
                for (n.finish = !0, x.queue(this, e, []), i && i.stop && i.stop.call(this, !0), 
                t = o.length; t--; ) o[t].elem === this && o[t].queue === e && (o[t].anim.stop(!0), 
                o.splice(t, 1));
                for (t = 0; a > t; t++) r[t] && r[t].finish && r[t].finish.call(this);
                delete n.finish;
            });
        }
    });
    function ir(e, t) {
        var n, r = {
            height: e
        }, i = 0;
        for (t = t ? 1 : 0; 4 > i; i += 2 - t) n = Zt[i], r["margin" + n] = r["padding" + n] = e;
        return t && (r.opacity = r.width = e), r;
    }
    x.each({
        slideDown: ir("show"),
        slideUp: ir("hide"),
        slideToggle: ir("toggle"),
        fadeIn: {
            opacity: "show"
        },
        fadeOut: {
            opacity: "hide"
        },
        fadeToggle: {
            opacity: "toggle"
        }
    }, function(e, t) {
        x.fn[e] = function(e, n, r) {
            return this.animate(t, e, n, r);
        };
    }), x.speed = function(e, t, n) {
        var r = e && "object" == typeof e ? x.extend({}, e) : {
            complete: n || !n && t || x.isFunction(e) && e,
            duration: e,
            easing: n && t || t && !x.isFunction(t) && t
        };
        return r.duration = x.fx.off ? 0 : "number" == typeof r.duration ? r.duration : r.duration in x.fx.speeds ? x.fx.speeds[r.duration] : x.fx.speeds._default, 
        (null == r.queue || r.queue === !0) && (r.queue = "fx"), r.old = r.complete, r.complete = function() {
            x.isFunction(r.old) && r.old.call(this), r.queue && x.dequeue(this, r.queue);
        }, r;
    }, x.easing = {
        linear: function(e) {
            return e;
        },
        swing: function(e) {
            return .5 - Math.cos(e * Math.PI) / 2;
        }
    }, x.timers = [], x.fx = rr.prototype.init, x.fx.tick = function() {
        var e, n = x.timers, r = 0;
        for (Xn = x.now(); n.length > r; r++) e = n[r], e() || n[r] !== e || n.splice(r--, 1);
        n.length || x.fx.stop(), Xn = t;
    }, x.fx.timer = function(e) {
        e() && x.timers.push(e) && x.fx.start();
    }, x.fx.interval = 13, x.fx.start = function() {
        Un || (Un = setInterval(x.fx.tick, x.fx.interval));
    }, x.fx.stop = function() {
        clearInterval(Un), Un = null;
    }, x.fx.speeds = {
        slow: 600,
        fast: 200,
        _default: 400
    }, x.fx.step = {}, x.expr && x.expr.filters && (x.expr.filters.animated = function(e) {
        return x.grep(x.timers, function(t) {
            return e === t.elem;
        }).length;
    }), x.fn.offset = function(e) {
        if (arguments.length) return e === t ? this : this.each(function(t) {
            x.offset.setOffset(this, e, t);
        });
        var n, r, o = {
            top: 0,
            left: 0
        }, a = this[0], s = a && a.ownerDocument;
        if (s) return n = s.documentElement, x.contains(n, a) ? (typeof a.getBoundingClientRect !== i && (o = a.getBoundingClientRect()), 
        r = or(s), {
            top: o.top + (r.pageYOffset || n.scrollTop) - (n.clientTop || 0),
            left: o.left + (r.pageXOffset || n.scrollLeft) - (n.clientLeft || 0)
        }) : o;
    }, x.offset = {
        setOffset: function(e, t, n) {
            var r = x.css(e, "position");
            "static" === r && (e.style.position = "relative");
            var i = x(e), o = i.offset(), a = x.css(e, "top"), s = x.css(e, "left"), l = ("absolute" === r || "fixed" === r) && x.inArray("auto", [ a, s ]) > -1, u = {}, c = {}, p, f;
            l ? (c = i.position(), p = c.top, f = c.left) : (p = parseFloat(a) || 0, f = parseFloat(s) || 0), 
            x.isFunction(t) && (t = t.call(e, n, o)), null != t.top && (u.top = t.top - o.top + p), 
            null != t.left && (u.left = t.left - o.left + f), "using" in t ? t.using.call(e, u) : i.css(u);
        }
    }, x.fn.extend({
        position: function() {
            if (this[0]) {
                var e, t, n = {
                    top: 0,
                    left: 0
                }, r = this[0];
                return "fixed" === x.css(r, "position") ? t = r.getBoundingClientRect() : (e = this.offsetParent(), 
                t = this.offset(), x.nodeName(e[0], "html") || (n = e.offset()), n.top += x.css(e[0], "borderTopWidth", !0), 
                n.left += x.css(e[0], "borderLeftWidth", !0)), {
                    top: t.top - n.top - x.css(r, "marginTop", !0),
                    left: t.left - n.left - x.css(r, "marginLeft", !0)
                };
            }
        },
        offsetParent: function() {
            return this.map(function() {
                var e = this.offsetParent || s;
                while (e && !x.nodeName(e, "html") && "static" === x.css(e, "position")) e = e.offsetParent;
                return e || s;
            });
        }
    }), x.each({
        scrollLeft: "pageXOffset",
        scrollTop: "pageYOffset"
    }, function(e, n) {
        var r = /Y/.test(n);
        x.fn[e] = function(i) {
            return x.access(this, function(e, i, o) {
                var a = or(e);
                return o === t ? a ? n in a ? a[n] : a.document.documentElement[i] : e[i] : (a ? a.scrollTo(r ? x(a).scrollLeft() : o, r ? o : x(a).scrollTop()) : e[i] = o, 
                t);
            }, e, i, arguments.length, null);
        };
    });
    function or(e) {
        return x.isWindow(e) ? e : 9 === e.nodeType ? e.defaultView || e.parentWindow : !1;
    }
    x.each({
        Height: "height",
        Width: "width"
    }, function(e, n) {
        x.each({
            padding: "inner" + e,
            content: n,
            "": "outer" + e
        }, function(r, i) {
            x.fn[i] = function(i, o) {
                var a = arguments.length && (r || "boolean" != typeof i), s = r || (i === !0 || o === !0 ? "margin" : "border");
                return x.access(this, function(n, r, i) {
                    var o;
                    return x.isWindow(n) ? n.document.documentElement["client" + e] : 9 === n.nodeType ? (o = n.documentElement, 
                    Math.max(n.body["scroll" + e], o["scroll" + e], n.body["offset" + e], o["offset" + e], o["client" + e])) : i === t ? x.css(n, r, s) : x.style(n, r, i, s);
                }, n, a ? i : t, a, null);
            };
        });
    }), x.fn.size = function() {
        return this.length;
    }, x.fn.andSelf = x.fn.addBack, "object" == typeof module && module && "object" == typeof module.exports ? module.exports = x : (e.jQuery = e.$ = x, 
    "function" == typeof define && define.amd && define("jquery", [], function() {
        return x;
    }));
})(window);

(function() {
    this.MooTools = {
        version: "1.4.5",
        build: "ab8ea8824dc3b24b6666867a2c4ed58ebb762cf0"
    };
    var typeOf = this.typeOf = function(item) {
        if (item == null) return "null";
        if (item.$family != null) return item.$family();
        if (item.nodeName) {
            if (item.nodeType == 1) return "element";
            if (item.nodeType == 3) return /\S/.test(item.nodeValue) ? "textnode" : "whitespace";
        } else if (typeof item.length == "number") {
            if (item.callee) return "arguments";
            if ("item" in item) return "collection";
        }
        return typeof item;
    };
    var instanceOf = this.instanceOf = function(item, object) {
        if (item == null) return false;
        var constructor = item.$constructor || item.constructor;
        while (constructor) {
            if (constructor === object) return true;
            constructor = constructor.parent;
        }
        if (!item.hasOwnProperty) return false;
        return item instanceof object;
    };
    var Function = this.Function;
    var enumerables = true;
    for (var i in {
        toString: 1
    }) enumerables = null;
    if (enumerables) enumerables = [ "hasOwnProperty", "valueOf", "isPrototypeOf", "propertyIsEnumerable", "toLocaleString", "toString", "constructor" ];
    Function.prototype.overloadSetter = function(usePlural) {
        var self = this;
        return function(a, b) {
            if (a == null) return this;
            if (usePlural || typeof a != "string") {
                for (var k in a) self.call(this, k, a[k]);
                if (enumerables) for (var i = enumerables.length; i--; ) {
                    k = enumerables[i];
                    if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
                }
            } else {
                self.call(this, a, b);
            }
            return this;
        };
    };
    Function.prototype.overloadGetter = function(usePlural) {
        var self = this;
        return function(a) {
            var args, result;
            if (typeof a != "string") args = a; else if (arguments.length > 1) args = arguments; else if (usePlural) args = [ a ];
            if (args) {
                result = {};
                for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
            } else {
                result = self.call(this, a);
            }
            return result;
        };
    };
    Function.prototype.extend = function(key, value) {
        this[key] = value;
    }.overloadSetter();
    Function.prototype.implement = function(key, value) {
        this.prototype[key] = value;
    }.overloadSetter();
    var slice = Array.prototype.slice;
    Function.from = function(item) {
        return typeOf(item) == "function" ? item : function() {
            return item;
        };
    };
    Array.from = function(item) {
        if (item == null) return [];
        return Type.isEnumerable(item) && typeof item != "string" ? typeOf(item) == "array" ? item : slice.call(item) : [ item ];
    };
    Number.from = function(item) {
        var number = parseFloat(item);
        return isFinite(number) ? number : null;
    };
    String.from = function(item) {
        return item + "";
    };
    Function.implement({
        hide: function() {
            this.$hidden = true;
            return this;
        },
        protect: function() {
            this.$protected = true;
            return this;
        }
    });
    var Type = this.Type = function(name, object) {
        if (name) {
            var lower = name.toLowerCase();
            var typeCheck = function(item) {
                return typeOf(item) == lower;
            };
            Type["is" + name] = typeCheck;
            if (object != null) {
                object.prototype.$family = function() {
                    return lower;
                }.hide();
            }
        }
        if (object == null) return null;
        object.extend(this);
        object.$constructor = Type;
        object.prototype.$constructor = object;
        return object;
    };
    var toString = Object.prototype.toString;
    Type.isEnumerable = function(item) {
        return item != null && typeof item.length == "number" && toString.call(item) != "[object Function]";
    };
    var hooks = {};
    var hooksOf = function(object) {
        var type = typeOf(object.prototype);
        return hooks[type] || (hooks[type] = []);
    };
    var implement = function(name, method) {
        if (method && method.$hidden) return;
        var hooks = hooksOf(this);
        for (var i = 0; i < hooks.length; i++) {
            var hook = hooks[i];
            if (typeOf(hook) == "type") implement.call(hook, name, method); else hook.call(this, name, method);
        }
        var previous = this.prototype[name];
        if (previous == null || !previous.$protected) this.prototype[name] = method;
        if (this[name] == null && typeOf(method) == "function") extend.call(this, name, function(item) {
            return method.apply(item, slice.call(arguments, 1));
        });
    };
    var extend = function(name, method) {
        if (method && method.$hidden) return;
        var previous = this[name];
        if (previous == null || !previous.$protected) this[name] = method;
    };
    Type.implement({
        implement: implement.overloadSetter(),
        extend: extend.overloadSetter(),
        alias: function(name, existing) {
            implement.call(this, name, this.prototype[existing]);
        }.overloadSetter(),
        mirror: function(hook) {
            hooksOf(this).push(hook);
            return this;
        }
    });
    new Type("Type", Type);
    var force = function(name, object, methods) {
        var isType = object != Object, prototype = object.prototype;
        if (isType) object = new Type(name, object);
        for (var i = 0, l = methods.length; i < l; i++) {
            var key = methods[i], generic = object[key], proto = prototype[key];
            if (generic) generic.protect();
            if (isType && proto) object.implement(key, proto.protect());
        }
        if (isType) {
            var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
            object.forEachMethod = function(fn) {
                if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++) {
                    fn.call(prototype, prototype[methods[i]], methods[i]);
                }
                for (var key in prototype) fn.call(prototype, prototype[key], key);
            };
        }
        return force;
    };
    force("String", String, [ "charAt", "charCodeAt", "concat", "indexOf", "lastIndexOf", "match", "quote", "replace", "search", "slice", "split", "substr", "substring", "trim", "toLowerCase", "toUpperCase" ])("Array", Array, [ "pop", "push", "reverse", "shift", "sort", "splice", "unshift", "concat", "join", "slice", "indexOf", "lastIndexOf", "filter", "forEach", "every", "map", "some", "reduce", "reduceRight" ])("Number", Number, [ "toExponential", "toFixed", "toLocaleString", "toPrecision" ])("Function", Function, [ "apply", "call", "bind" ])("RegExp", RegExp, [ "exec", "test" ])("Object", Object, [ "create", "defineProperty", "defineProperties", "keys", "getPrototypeOf", "getOwnPropertyDescriptor", "getOwnPropertyNames", "preventExtensions", "isExtensible", "seal", "isSealed", "freeze", "isFrozen" ])("Date", Date, [ "now" ]);
    Object.extend = extend.overloadSetter();
    Date.extend("now", function() {
        return +new Date();
    });
    new Type("Boolean", Boolean);
    Number.prototype.$family = function() {
        return isFinite(this) ? "number" : "null";
    }.hide();
    Number.extend("random", function(min, max) {
        return Math.floor(Math.random() * (max - min + 1) + min);
    });
    var hasOwnProperty = Object.prototype.hasOwnProperty;
    Object.extend("forEach", function(object, fn, bind) {
        for (var key in object) {
            if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
        }
    });
    Object.each = Object.forEach;
    Array.implement({
        forEach: function(fn, bind) {
            for (var i = 0, l = this.length; i < l; i++) {
                if (i in this) fn.call(bind, this[i], i, this);
            }
        },
        each: function(fn, bind) {
            Array.forEach(this, fn, bind);
            return this;
        }
    });
    var cloneOf = function(item) {
        switch (typeOf(item)) {
          case "array":
            return item.clone();

          case "object":
            return Object.clone(item);

          default:
            return item;
        }
    };
    Array.implement("clone", function() {
        var i = this.length, clone = new Array(i);
        while (i--) clone[i] = cloneOf(this[i]);
        return clone;
    });
    var mergeOne = function(source, key, current) {
        switch (typeOf(current)) {
          case "object":
            if (typeOf(source[key]) == "object") Object.merge(source[key], current); else source[key] = Object.clone(current);
            break;

          case "array":
            source[key] = current.clone();
            break;

          default:
            source[key] = current;
        }
        return source;
    };
    Object.extend({
        merge: function(source, k, v) {
            if (typeOf(k) == "string") return mergeOne(source, k, v);
            for (var i = 1, l = arguments.length; i < l; i++) {
                var object = arguments[i];
                for (var key in object) mergeOne(source, key, object[key]);
            }
            return source;
        },
        clone: function(object) {
            var clone = {};
            for (var key in object) clone[key] = cloneOf(object[key]);
            return clone;
        },
        append: function(original) {
            for (var i = 1, l = arguments.length; i < l; i++) {
                var extended = arguments[i] || {};
                for (var key in extended) original[key] = extended[key];
            }
            return original;
        }
    });
    [ "Object", "WhiteSpace", "TextNode", "Collection", "Arguments" ].each(function(name) {
        new Type(name);
    });
    var UID = Date.now();
    String.extend("uniqueID", function() {
        return (UID++).toString(36);
    });
})();

Array.implement({
    every: function(fn, bind) {
        for (var i = 0, l = this.length >>> 0; i < l; i++) {
            if (i in this && !fn.call(bind, this[i], i, this)) return false;
        }
        return true;
    },
    filter: function(fn, bind) {
        var results = [];
        for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this) {
            value = this[i];
            if (fn.call(bind, value, i, this)) results.push(value);
        }
        return results;
    },
    indexOf: function(item, from) {
        var length = this.length >>> 0;
        for (var i = from < 0 ? Math.max(0, length + from) : from || 0; i < length; i++) {
            if (this[i] === item) return i;
        }
        return -1;
    },
    map: function(fn, bind) {
        var length = this.length >>> 0, results = Array(length);
        for (var i = 0; i < length; i++) {
            if (i in this) results[i] = fn.call(bind, this[i], i, this);
        }
        return results;
    },
    some: function(fn, bind) {
        for (var i = 0, l = this.length >>> 0; i < l; i++) {
            if (i in this && fn.call(bind, this[i], i, this)) return true;
        }
        return false;
    },
    clean: function() {
        return this.filter(function(item) {
            return item != null;
        });
    },
    invoke: function(methodName) {
        var args = Array.slice(arguments, 1);
        return this.map(function(item) {
            return item[methodName].apply(item, args);
        });
    },
    associate: function(keys) {
        var obj = {}, length = Math.min(this.length, keys.length);
        for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
        return obj;
    },
    link: function(object) {
        var result = {};
        for (var i = 0, l = this.length; i < l; i++) {
            for (var key in object) {
                if (object[key](this[i])) {
                    result[key] = this[i];
                    delete object[key];
                    break;
                }
            }
        }
        return result;
    },
    contains: function(item, from) {
        return this.indexOf(item, from) != -1;
    },
    append: function(array) {
        this.push.apply(this, array);
        return this;
    },
    getLast: function() {
        return this.length ? this[this.length - 1] : null;
    },
    getRandom: function() {
        return this.length ? this[Number.random(0, this.length - 1)] : null;
    },
    include: function(item) {
        if (!this.contains(item)) this.push(item);
        return this;
    },
    combine: function(array) {
        for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
        return this;
    },
    erase: function(item) {
        for (var i = this.length; i--; ) {
            if (this[i] === item) this.splice(i, 1);
        }
        return this;
    },
    empty: function() {
        this.length = 0;
        return this;
    },
    flatten: function() {
        var array = [];
        for (var i = 0, l = this.length; i < l; i++) {
            var type = typeOf(this[i]);
            if (type == "null") continue;
            array = array.concat(type == "array" || type == "collection" || type == "arguments" || instanceOf(this[i], Array) ? Array.flatten(this[i]) : this[i]);
        }
        return array;
    },
    pick: function() {
        for (var i = 0, l = this.length; i < l; i++) {
            if (this[i] != null) return this[i];
        }
        return null;
    },
    hexToRgb: function(array) {
        if (this.length != 3) return null;
        var rgb = this.map(function(value) {
            if (value.length == 1) value += value;
            return value.toInt(16);
        });
        return array ? rgb : "rgb(" + rgb + ")";
    },
    rgbToHex: function(array) {
        if (this.length < 3) return null;
        if (this.length == 4 && this[3] == 0 && !array) return "transparent";
        var hex = [];
        for (var i = 0; i < 3; i++) {
            var bit = (this[i] - 0).toString(16);
            hex.push(bit.length == 1 ? "0" + bit : bit);
        }
        return array ? hex : "#" + hex.join("");
    }
});

Function.extend({
    attempt: function() {
        for (var i = 0, l = arguments.length; i < l; i++) {
            try {
                return arguments[i]();
            } catch (e) {}
        }
        return null;
    }
});

Function.implement({
    attempt: function(args, bind) {
        try {
            return this.apply(bind, Array.from(args));
        } catch (e) {}
        return null;
    },
    bind: function(that) {
        var self = this, args = arguments.length > 1 ? Array.slice(arguments, 1) : null, F = function() {};
        var bound = function() {
            var context = that, length = arguments.length;
            if (this instanceof bound) {
                F.prototype = self.prototype;
                context = new F();
            }
            var result = !args && !length ? self.call(context) : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
            return context == that ? result : context;
        };
        return bound;
    },
    pass: function(args, bind) {
        var self = this;
        if (args != null) args = Array.from(args);
        return function() {
            return self.apply(bind, args || arguments);
        };
    },
    delay: function(delay, bind, args) {
        return setTimeout(this.pass(args == null ? [] : args, bind), delay);
    },
    periodical: function(periodical, bind, args) {
        return setInterval(this.pass(args == null ? [] : args, bind), periodical);
    }
});

Number.implement({
    limit: function(min, max) {
        return Math.min(max, Math.max(min, this));
    },
    round: function(precision) {
        precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
        return Math.round(this * precision) / precision;
    },
    times: function(fn, bind) {
        for (var i = 0; i < this; i++) fn.call(bind, i, this);
    },
    toFloat: function() {
        return parseFloat(this);
    },
    toInt: function(base) {
        return parseInt(this, base || 10);
    }
});

Number.alias("each", "times");

(function(math) {
    var methods = {};
    math.each(function(name) {
        if (!Number[name]) methods[name] = function() {
            return Math[name].apply(null, [ this ].concat(Array.from(arguments)));
        };
    });
    Number.implement(methods);
})([ "abs", "acos", "asin", "atan", "atan2", "ceil", "cos", "exp", "floor", "log", "max", "min", "pow", "sin", "sqrt", "tan" ]);

String.implement({
    test: function(regex, params) {
        return (typeOf(regex) == "regexp" ? regex : new RegExp("" + regex, params)).test(this);
    },
    contains: function(string, separator) {
        return separator ? (separator + this + separator).indexOf(separator + string + separator) > -1 : String(this).indexOf(string) > -1;
    },
    trim: function() {
        return String(this).replace(/^\s+|\s+$/g, "");
    },
    clean: function() {
        return String(this).replace(/\s+/g, " ").trim();
    },
    camelCase: function() {
        return String(this).replace(/-\D/g, function(match) {
            return match.charAt(1).toUpperCase();
        });
    },
    hyphenate: function() {
        return String(this).replace(/[A-Z]/g, function(match) {
            return "-" + match.charAt(0).toLowerCase();
        });
    },
    capitalize: function() {
        return String(this).replace(/\b[a-z]/g, function(match) {
            return match.toUpperCase();
        });
    },
    escapeRegExp: function() {
        return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, "\\$1");
    },
    toInt: function(base) {
        return parseInt(this, base || 10);
    },
    toFloat: function() {
        return parseFloat(this);
    },
    hexToRgb: function(array) {
        var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
        return hex ? hex.slice(1).hexToRgb(array) : null;
    },
    rgbToHex: function(array) {
        var rgb = String(this).match(/\d{1,3}/g);
        return rgb ? rgb.rgbToHex(array) : null;
    },
    substitute: function(object, regexp) {
        return String(this).replace(regexp || /\\?\{([^{}]+)\}/g, function(match, name) {
            if (match.charAt(0) == "\\") return match.slice(1);
            return object[name] != null ? object[name] : "";
        });
    }
});

(function() {
    var document = this.document;
    var window = document.window = this;
    var ua = navigator.userAgent.toLowerCase(), platform = navigator.platform.toLowerCase(), UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [ null, "unknown", 0 ], mode = UA[1] == "ie" && document.documentMode;
    var Browser = this.Browser = {
        extend: Function.prototype.extend,
        name: UA[1] == "version" ? UA[3] : UA[1],
        version: mode || parseFloat(UA[1] == "opera" && UA[4] ? UA[4] : UA[2]),
        Platform: {
            name: ua.match(/ip(?:ad|od|hone)/) ? "ios" : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || [ "other" ])[0]
        },
        Features: {
            xpath: !!document.evaluate,
            air: !!window.runtime,
            query: !!document.querySelector,
            json: !!window.JSON
        },
        Plugins: {}
    };
    Browser[Browser.name] = true;
    Browser[Browser.name + parseInt(Browser.version, 10)] = true;
    Browser.Platform[Browser.Platform.name] = true;
    Browser.Request = function() {
        var XMLHTTP = function() {
            return new XMLHttpRequest();
        };
        var MSXML2 = function() {
            return new ActiveXObject("MSXML2.XMLHTTP");
        };
        var MSXML = function() {
            return new ActiveXObject("Microsoft.XMLHTTP");
        };
        return Function.attempt(function() {
            XMLHTTP();
            return XMLHTTP;
        }, function() {
            MSXML2();
            return MSXML2;
        }, function() {
            MSXML();
            return MSXML;
        });
    }();
    Browser.Features.xhr = !!Browser.Request;
    var version = (Function.attempt(function() {
        return navigator.plugins["Shockwave Flash"].description;
    }, function() {
        return new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version");
    }) || "0 r0").match(/\d+/g);
    Browser.Plugins.Flash = {
        version: Number(version[0] || "0." + version[1]) || 0,
        build: Number(version[2]) || 0
    };
    Browser.exec = function(text) {
        if (!text) return text;
        if (window.execScript) {
            window.execScript(text);
        } else {
            var script = document.createElement("script");
            script.setAttribute("type", "text/javascript");
            script.text = text;
            document.head.appendChild(script);
            document.head.removeChild(script);
        }
        return text;
    };
    String.implement("stripScripts", function(exec) {
        var scripts = "";
        var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, code) {
            scripts += code + "\n";
            return "";
        });
        if (exec === true) Browser.exec(scripts); else if (typeOf(exec) == "function") exec(scripts, text);
        return text;
    });
    Browser.extend({
        Document: this.Document,
        Window: this.Window,
        Element: this.Element,
        Event: this.Event
    });
    this.Window = this.$constructor = new Type("Window", function() {});
    this.$family = Function.from("window").hide();
    Window.mirror(function(name, method) {
        window[name] = method;
    });
    this.Document = document.$constructor = new Type("Document", function() {});
    document.$family = Function.from("document").hide();
    Document.mirror(function(name, method) {
        document[name] = method;
    });
    document.html = document.documentElement;
    if (!document.head) document.head = document.getElementsByTagName("head")[0];
    if (document.execCommand) try {
        document.execCommand("BackgroundImageCache", false, true);
    } catch (e) {}
    if (this.attachEvent && !this.addEventListener) {
        var unloadEvent = function() {
            this.detachEvent("onunload", unloadEvent);
            document.head = document.html = document.window = null;
        };
        this.attachEvent("onunload", unloadEvent);
    }
    var arrayFrom = Array.from;
    try {
        arrayFrom(document.html.childNodes);
    } catch (e) {
        Array.from = function(item) {
            if (typeof item != "string" && Type.isEnumerable(item) && typeOf(item) != "array") {
                var i = item.length, array = new Array(i);
                while (i--) array[i] = item[i];
                return array;
            }
            return arrayFrom(item);
        };
        var prototype = Array.prototype, slice = prototype.slice;
        [ "pop", "push", "reverse", "shift", "sort", "splice", "unshift", "concat", "join", "slice" ].each(function(name) {
            var method = prototype[name];
            Array[name] = function(item) {
                return method.apply(Array.from(item), slice.call(arguments, 1));
            };
        });
    }
})();

if (typeof JSON == "undefined") this.JSON = {};

(function() {
    var special = {
        "\b": "\\b",
        "	": "\\t",
        "\n": "\\n",
        "\f": "\\f",
        "\r": "\\r",
        '"': '\\"',
        "\\": "\\\\"
    };
    var escape = function(chr) {
        return special[chr] || "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).slice(-4);
    };
    JSON.validate = function(string) {
        string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]").replace(/(?:^|:|,)(?:\s*\[)+/g, "");
        return /^[\],:{}\s]*$/.test(string);
    };
    JSON.encode = JSON.stringify ? function(obj) {
        return JSON.stringify(obj);
    } : function(obj) {
        if (obj && obj.toJSON) obj = obj.toJSON();
        switch (typeOf(obj)) {
          case "string":
            return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"';

          case "array":
            return "[" + obj.map(JSON.encode).clean() + "]";

          case "object":
          case "hash":
            var string = [];
            Object.each(obj, function(value, key) {
                var json = JSON.encode(value);
                if (json) string.push(JSON.encode(key) + ":" + json);
            });
            return "{" + string + "}";

          case "number":
          case "boolean":
            return "" + obj;

          case "null":
            return "null";
        }
        return null;
    };
    JSON.decode = function(string, secure) {
        if (!string || typeOf(string) != "string") return null;
        if (secure || JSON.secure) {
            if (JSON.parse) return JSON.parse(string);
            if (!JSON.validate(string)) throw new Error("JSON could not decode the input; security is enabled and the value is not secure.");
        }
        return eval("(" + string + ")");
    };
})();

(function($) {
    $.extend({
        tablesorter: new function() {
            var parsers = [], widgets = [];
            this.defaults = {
                cssHeader: "header",
                cssAsc: "headerSortUp",
                cssDesc: "headerSortDown",
                cssChildRow: "expand-child",
                sortInitialOrder: "asc",
                sortMultiSortKey: "shiftKey",
                sortForce: null,
                sortAppend: null,
                sortLocaleCompare: true,
                textExtraction: "simple",
                parsers: {},
                widgets: [],
                widgetZebra: {
                    css: [ "even", "odd" ]
                },
                headers: {},
                widthFixed: false,
                cancelSelection: true,
                sortList: [],
                headerList: [],
                dateFormat: "us",
                decimal: "/.|,/g",
                onRenderHeader: null,
                selectorHeaders: "thead th",
                debug: false
            };
            function benchmark(s, d) {
                log(s + "," + (new Date().getTime() - d.getTime()) + "ms");
            }
            this.benchmark = benchmark;
            function log(s) {
                if (typeof console != "undefined" && typeof console.debug != "undefined") {
                    console.log(s);
                } else {
                    alert(s);
                }
            }
            function buildParserCache(table, $headers) {
                if (table.config.debug) {
                    var parsersDebug = "";
                }
                if (table.tBodies.length == 0) return;
                var rows = table.tBodies[0].rows;
                if (rows[0]) {
                    var list = [], cells = rows[0].cells, l = cells.length;
                    for (var i = 0; i < l; i++) {
                        var p = false;
                        if ($.metadata && $($headers[i]).metadata() && $($headers[i]).metadata().sorter) {
                            p = getParserById($($headers[i]).metadata().sorter);
                        } else if (table.config.headers[i] && table.config.headers[i].sorter) {
                            p = getParserById(table.config.headers[i].sorter);
                        }
                        if (!p) {
                            p = detectParserForColumn(table, rows, -1, i);
                        }
                        if (table.config.debug) {
                            parsersDebug += "column:" + i + " parser:" + p.id + "\n";
                        }
                        list.push(p);
                    }
                }
                if (table.config.debug) {
                    log(parsersDebug);
                }
                return list;
            }
            function detectParserForColumn(table, rows, rowIndex, cellIndex) {
                var l = parsers.length, node = false, nodeValue = false, keepLooking = true;
                while (nodeValue == "" && keepLooking) {
                    rowIndex++;
                    if (rows[rowIndex]) {
                        node = getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex);
                        nodeValue = trimAndGetNodeText(table.config, node);
                        if (table.config.debug) {
                            log("Checking if value was empty on row:" + rowIndex);
                        }
                    } else {
                        keepLooking = false;
                    }
                }
                for (var i = 1; i < l; i++) {
                    if (parsers[i].is(nodeValue, table, node)) {
                        return parsers[i];
                    }
                }
                return parsers[0];
            }
            function getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex) {
                return rows[rowIndex].cells[cellIndex];
            }
            function trimAndGetNodeText(config, node) {
                return $.trim(getElementText(config, node));
            }
            function getParserById(name) {
                var l = parsers.length;
                for (var i = 0; i < l; i++) {
                    if (parsers[i].id.toLowerCase() == name.toLowerCase()) {
                        return parsers[i];
                    }
                }
                return false;
            }
            function buildCache(table) {
                if (table.config.debug) {
                    var cacheTime = new Date();
                }
                var totalRows = table.tBodies[0] && table.tBodies[0].rows.length || 0, totalCells = table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length || 0, parsers = table.config.parsers, cache = {
                    row: [],
                    normalized: []
                };
                for (var i = 0; i < totalRows; ++i) {
                    var c = $(table.tBodies[0].rows[i]), cols = [];
                    if (c.hasClass(table.config.cssChildRow)) {
                        cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c);
                        continue;
                    }
                    cache.row.push(c);
                    for (var j = 0; j < totalCells; ++j) {
                        cols.push(parsers[j].format(getElementText(table.config, c[0].cells[j]), table, c[0].cells[j]));
                    }
                    cols.push(cache.normalized.length);
                    cache.normalized.push(cols);
                    cols = null;
                }
                if (table.config.debug) {
                    benchmark("Building cache for " + totalRows + " rows:", cacheTime);
                }
                return cache;
            }
            function getElementText(config, node) {
                var text = "";
                if (!node) return "";
                if (!config.supportsTextContent) config.supportsTextContent = node.textContent || false;
                if (config.textExtraction == "simple") {
                    if (config.supportsTextContent) {
                        text = node.textContent;
                    } else {
                        if (node.childNodes[0] && node.childNodes[0].hasChildNodes()) {
                            text = node.childNodes[0].innerHTML;
                        } else {
                            text = node.innerHTML;
                        }
                    }
                } else {
                    if (typeof config.textExtraction == "function") {
                        text = config.textExtraction(node);
                    } else {
                        text = $(node).text();
                    }
                }
                return text;
            }
            function appendToTable(table, cache) {
                if (table.config.debug) {
                    var appendTime = new Date();
                }
                var c = cache, r = c.row, n = c.normalized, totalRows = n.length, checkCell = n[0].length - 1, tableBody = $(table.tBodies[0]), rows = [];
                for (var i = 0; i < totalRows; i++) {
                    var pos = n[i][checkCell];
                    rows.push(r[pos]);
                    if (!table.config.appender) {
                        var l = r[pos].length;
                        for (var j = 0; j < l; j++) {
                            tableBody[0].appendChild(r[pos][j]);
                        }
                    }
                }
                if (table.config.appender) {
                    table.config.appender(table, rows);
                }
                rows = null;
                if (table.config.debug) {
                    benchmark("Rebuilt table:", appendTime);
                }
                applyWidget(table);
                setTimeout(function() {
                    $(table).trigger("sortEnd");
                }, 0);
            }
            function buildHeaders(table) {
                if (table.config.debug) {
                    var time = new Date();
                }
                var meta = $.metadata ? true : false;
                var header_index = computeTableHeaderCellIndexes(table);
                $tableHeaders = $(table.config.selectorHeaders, table).each(function(index) {
                    this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex];
                    this.order = formatSortingOrder(table.config.sortInitialOrder);
                    this.count = this.order;
                    if (checkHeaderMetadata(this) || checkHeaderOptions(table, index)) this.sortDisabled = true;
                    if (checkHeaderOptionsSortingLocked(table, index)) this.order = this.lockedOrder = checkHeaderOptionsSortingLocked(table, index);
                    if (!this.sortDisabled) {
                        var $th = $(this).addClass(table.config.cssHeader);
                        if (table.config.onRenderHeader) table.config.onRenderHeader.apply($th);
                    }
                    table.config.headerList[index] = this;
                });
                if (table.config.debug) {
                    benchmark("Built headers:", time);
                    log($tableHeaders);
                }
                return $tableHeaders;
            }
            function computeTableHeaderCellIndexes(t) {
                var matrix = [];
                var lookup = {};
                var thead = t.getElementsByTagName("THEAD")[0];
                var trs = thead.getElementsByTagName("TR");
                for (var i = 0; i < trs.length; i++) {
                    var cells = trs[i].cells;
                    for (var j = 0; j < cells.length; j++) {
                        var c = cells[j];
                        var rowIndex = c.parentNode.rowIndex;
                        var cellId = rowIndex + "-" + c.cellIndex;
                        var rowSpan = c.rowSpan || 1;
                        var colSpan = c.colSpan || 1;
                        var firstAvailCol;
                        if (typeof matrix[rowIndex] == "undefined") {
                            matrix[rowIndex] = [];
                        }
                        for (var k = 0; k < matrix[rowIndex].length + 1; k++) {
                            if (typeof matrix[rowIndex][k] == "undefined") {
                                firstAvailCol = k;
                                break;
                            }
                        }
                        lookup[cellId] = firstAvailCol;
                        for (var k = rowIndex; k < rowIndex + rowSpan; k++) {
                            if (typeof matrix[k] == "undefined") {
                                matrix[k] = [];
                            }
                            var matrixrow = matrix[k];
                            for (var l = firstAvailCol; l < firstAvailCol + colSpan; l++) {
                                matrixrow[l] = "x";
                            }
                        }
                    }
                }
                return lookup;
            }
            function checkCellColSpan(table, rows, row) {
                var arr = [], r = table.tHead.rows, c = r[row].cells;
                for (var i = 0; i < c.length; i++) {
                    var cell = c[i];
                    if (cell.colSpan > 1) {
                        arr = arr.concat(checkCellColSpan(table, headerArr, row++));
                    } else {
                        if (table.tHead.length == 1 || cell.rowSpan > 1 || !r[row + 1]) {
                            arr.push(cell);
                        }
                    }
                }
                return arr;
            }
            function checkHeaderMetadata(cell) {
                if ($.metadata && $(cell).metadata().sorter === false) {
                    return true;
                }
                return false;
            }
            function checkHeaderOptions(table, i) {
                if (table.config.headers[i] && table.config.headers[i].sorter === false) {
                    return true;
                }
                return false;
            }
            function checkHeaderOptionsSortingLocked(table, i) {
                if (table.config.headers[i] && table.config.headers[i].lockedOrder) return table.config.headers[i].lockedOrder;
                return false;
            }
            function applyWidget(table) {
                var c = table.config.widgets;
                var l = c.length;
                for (var i = 0; i < l; i++) {
                    getWidgetById(c[i]).format(table);
                }
            }
            function getWidgetById(name) {
                var l = widgets.length;
                for (var i = 0; i < l; i++) {
                    if (widgets[i].id.toLowerCase() == name.toLowerCase()) {
                        return widgets[i];
                    }
                }
            }
            function formatSortingOrder(v) {
                if (typeof v != "Number") {
                    return v.toLowerCase() == "desc" ? 1 : 0;
                } else {
                    return v == 1 ? 1 : 0;
                }
            }
            function isValueInArray(v, a) {
                var l = a.length;
                for (var i = 0; i < l; i++) {
                    if (a[i][0] == v) {
                        return true;
                    }
                }
                return false;
            }
            function setHeadersCss(table, $headers, list, css) {
                $headers.removeClass(css[0]).removeClass(css[1]);
                var h = [];
                $headers.each(function(offset) {
                    if (!this.sortDisabled) {
                        h[this.column] = $(this);
                    }
                });
                var l = list.length;
                for (var i = 0; i < l; i++) {
                    h[list[i][0]].addClass(css[list[i][1]]);
                }
            }
            function fixColumnWidth(table, $headers) {
                var c = table.config;
                if (c.widthFixed) {
                    var colgroup = $("<colgroup>");
                    $("tr:first td", table.tBodies[0]).each(function() {
                        colgroup.append($("<col>").css("width", $(this).width()));
                    });
                    $(table).prepend(colgroup);
                }
            }
            function updateHeaderSortCount(table, sortList) {
                var c = table.config, l = sortList.length;
                for (var i = 0; i < l; i++) {
                    var s = sortList[i], o = c.headerList[s[0]];
                    o.count = s[1];
                    o.count++;
                }
            }
            function multisort(table, sortList, cache) {
                if (table.config.debug) {
                    var sortTime = new Date();
                }
                var dynamicExp = "var sortWrapper = function(a,b) {", l = sortList.length;
                for (var i = 0; i < l; i++) {
                    var c = sortList[i][0];
                    var order = sortList[i][1];
                    var s = table.config.parsers[c].type == "text" ? order == 0 ? makeSortFunction("text", "asc", c) : makeSortFunction("text", "desc", c) : order == 0 ? makeSortFunction("numeric", "asc", c) : makeSortFunction("numeric", "desc", c);
                    var e = "e" + i;
                    dynamicExp += "var " + e + " = " + s;
                    dynamicExp += "if(" + e + ") { return " + e + "; } ";
                    dynamicExp += "else { ";
                }
                var orgOrderCol = cache.normalized[0].length - 1;
                dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";
                for (var i = 0; i < l; i++) {
                    dynamicExp += "}; ";
                }
                dynamicExp += "return 0; ";
                dynamicExp += "}; ";
                if (table.config.debug) {
                    benchmark("Evaling expression:" + dynamicExp, new Date());
                }
                eval(dynamicExp);
                cache.normalized.sort(sortWrapper);
                if (table.config.debug) {
                    benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime);
                }
                return cache;
            }
            function makeSortFunction(type, direction, index) {
                var a = "a[" + index + "]", b = "b[" + index + "]";
                if (type == "text" && direction == "asc") {
                    return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + a + " < " + b + ") ? -1 : 1 )));";
                } else if (type == "text" && direction == "desc") {
                    return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + b + " < " + a + ") ? -1 : 1 )));";
                } else if (type == "numeric" && direction == "asc") {
                    return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + a + " - " + b + "));";
                } else if (type == "numeric" && direction == "desc") {
                    return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + b + " - " + a + "));";
                }
            }
            function makeSortText(i) {
                return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));";
            }
            function makeSortTextDesc(i) {
                return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));";
            }
            function makeSortNumeric(i) {
                return "a[" + i + "]-b[" + i + "];";
            }
            function makeSortNumericDesc(i) {
                return "b[" + i + "]-a[" + i + "];";
            }
            function sortText(a, b) {
                if (table.config.sortLocaleCompare) return a.localeCompare(b);
                return a < b ? -1 : a > b ? 1 : 0;
            }
            function sortTextDesc(a, b) {
                if (table.config.sortLocaleCompare) return b.localeCompare(a);
                return b < a ? -1 : b > a ? 1 : 0;
            }
            function sortNumeric(a, b) {
                return a - b;
            }
            function sortNumericDesc(a, b) {
                return b - a;
            }
            function getCachedSortType(parsers, i) {
                return parsers[i].type;
            }
            this.construct = function(settings) {
                return this.each(function() {
                    if (!this.tHead || !this.tBodies) return;
                    var $this, $document, $headers, cache, config, shiftDown = 0, sortOrder;
                    this.config = {};
                    config = $.extend(this.config, $.tablesorter.defaults, settings);
                    $this = $(this);
                    $.data(this, "tablesorter", config);
                    $headers = buildHeaders(this);
                    this.config.parsers = buildParserCache(this, $headers);
                    cache = buildCache(this);
                    var sortCSS = [ config.cssDesc, config.cssAsc ];
                    fixColumnWidth(this);
                    $headers.click(function(e) {
                        var totalRows = $this[0].tBodies[0] && $this[0].tBodies[0].rows.length || 0;
                        if (!this.sortDisabled && totalRows > 0) {
                            $this.trigger("sortStart");
                            var $cell = $(this);
                            var i = this.column;
                            this.order = this.count++ % 2;
                            if (this.lockedOrder) this.order = this.lockedOrder;
                            if (!e[config.sortMultiSortKey]) {
                                config.sortList = [];
                                if (config.sortForce != null) {
                                    var a = config.sortForce;
                                    for (var j = 0; j < a.length; j++) {
                                        if (a[j][0] != i) {
                                            config.sortList.push(a[j]);
                                        }
                                    }
                                }
                                config.sortList.push([ i, this.order ]);
                            } else {
                                if (isValueInArray(i, config.sortList)) {
                                    for (var j = 0; j < config.sortList.length; j++) {
                                        var s = config.sortList[j], o = config.headerList[s[0]];
                                        if (s[0] == i) {
                                            o.count = s[1];
                                            o.count++;
                                            s[1] = o.count % 2;
                                        }
                                    }
                                } else {
                                    config.sortList.push([ i, this.order ]);
                                }
                            }
                            setTimeout(function() {
                                setHeadersCss($this[0], $headers, config.sortList, sortCSS);
                                appendToTable($this[0], multisort($this[0], config.sortList, cache));
                            }, 1);
                            return false;
                        }
                    }).mousedown(function() {
                        if (config.cancelSelection) {
                            this.onselectstart = function() {
                                return false;
                            };
                            return false;
                        }
                    });
                    $this.bind("update", function() {
                        var me = this;
                        setTimeout(function() {
                            me.config.parsers = buildParserCache(me, $headers);
                            cache = buildCache(me);
                        }, 1);
                    }).bind("updateCell", function(e, cell) {
                        var config = this.config;
                        var pos = [ cell.parentNode.rowIndex - 1, cell.cellIndex ];
                        cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format(getElementText(config, cell), cell);
                    }).bind("sorton", function(e, list) {
                        $(this).trigger("sortStart");
                        config.sortList = list;
                        var sortList = config.sortList;
                        updateHeaderSortCount(this, sortList);
                        setHeadersCss(this, $headers, sortList, sortCSS);
                        appendToTable(this, multisort(this, sortList, cache));
                    }).bind("appendCache", function() {
                        appendToTable(this, cache);
                    }).bind("applyWidgetId", function(e, id) {
                        getWidgetById(id).format(this);
                    }).bind("applyWidgets", function() {
                        applyWidget(this);
                    });
                    if ($.metadata && $(this).metadata() && $(this).metadata().sortlist) {
                        config.sortList = $(this).metadata().sortlist;
                    }
                    if (config.sortList.length > 0) {
                        $this.trigger("sorton", [ config.sortList ]);
                    }
                    applyWidget(this);
                });
            };
            this.addParser = function(parser) {
                var l = parsers.length, a = true;
                for (var i = 0; i < l; i++) {
                    if (parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
                        a = false;
                    }
                }
                if (a) {
                    parsers.push(parser);
                }
            };
            this.addWidget = function(widget) {
                widgets.push(widget);
            };
            this.formatFloat = function(s) {
                var i = parseFloat(s);
                return isNaN(i) ? 0 : i;
            };
            this.formatInt = function(s) {
                var i = parseInt(s);
                return isNaN(i) ? 0 : i;
            };
            this.isDigit = function(s, config) {
                return /^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g, "")));
            };
            this.clearTableBody = function(table) {
                if ($.browser.msie) {
                    function empty() {
                        while (this.firstChild) this.removeChild(this.firstChild);
                    }
                    empty.apply(table.tBodies[0]);
                } else {
                    table.tBodies[0].innerHTML = "";
                }
            };
        }()
    });
    $.fn.extend({
        tablesorter: $.tablesorter.construct
    });
    var ts = $.tablesorter;
    ts.addParser({
        id: "text",
        is: function(s) {
            return true;
        },
        format: function(s) {
            return $.trim(s.toLocaleLowerCase());
        },
        type: "text"
    });
    ts.addParser({
        id: "digit",
        is: function(s, table) {
            var c = table.config;
            return $.tablesorter.isDigit(s, c);
        },
        format: function(s) {
            return $.tablesorter.formatFloat(s);
        },
        type: "numeric"
    });
    ts.addParser({
        id: "currency",
        is: function(s) {
            return /^[£$€?.]/.test(s);
        },
        format: function(s) {
            return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g), ""));
        },
        type: "numeric"
    });
    ts.addParser({
        id: "ipAddress",
        is: function(s) {
            return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);
        },
        format: function(s) {
            var a = s.split("."), r = "", l = a.length;
            for (var i = 0; i < l; i++) {
                var item = a[i];
                if (item.length == 2) {
                    r += "0" + item;
                } else {
                    r += item;
                }
            }
            return $.tablesorter.formatFloat(r);
        },
        type: "numeric"
    });
    ts.addParser({
        id: "url",
        is: function(s) {
            return /^(https?|ftp|file):\/\/$/.test(s);
        },
        format: function(s) {
            return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), ""));
        },
        type: "text"
    });
    ts.addParser({
        id: "isoDate",
        is: function(s) {
            return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);
        },
        format: function(s) {
            return $.tablesorter.formatFloat(s != "" ? new Date(s.replace(new RegExp(/-/g), "/")).getTime() : "0");
        },
        type: "numeric"
    });
    ts.addParser({
        id: "percent",
        is: function(s) {
            return /\%$/.test($.trim(s));
        },
        format: function(s) {
            return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g), ""));
        },
        type: "numeric"
    });
    ts.addParser({
        id: "usLongDate",
        is: function(s) {
            return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));
        },
        format: function(s) {
            return $.tablesorter.formatFloat(new Date(s).getTime());
        },
        type: "numeric"
    });
    ts.addParser({
        id: "shortDate",
        is: function(s) {
            return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);
        },
        format: function(s, table) {
            var c = table.config;
            s = s.replace(/\-/g, "/");
            if (c.dateFormat == "us") {
                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2");
            } else if (c.dateFormat == "uk") {
                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1");
            } else if (c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3");
            }
            return $.tablesorter.formatFloat(new Date(s).getTime());
        },
        type: "numeric"
    });
    ts.addParser({
        id: "time",
        is: function(s) {
            return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
        },
        format: function(s) {
            return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime());
        },
        type: "numeric"
    });
    ts.addParser({
        id: "metadata",
        is: function(s) {
            return false;
        },
        format: function(s, table, cell) {
            var c = table.config, p = !c.parserMetadataName ? "sortValue" : c.parserMetadataName;
            return $(cell).metadata()[p];
        },
        type: "numeric"
    });
    ts.addWidget({
        id: "zebra",
        format: function(table) {
            if (table.config.debug) {
                var time = new Date();
            }
            var $tr, row = -1, odd;
            $("tr:visible", table.tBodies[0]).each(function(i) {
                $tr = $(this);
                if (!$tr.hasClass(table.config.cssChildRow)) row++;
                odd = row % 2 == 0;
                $tr.removeClass(table.config.widgetZebra.css[odd ? 0 : 1]).addClass(table.config.widgetZebra.css[odd ? 1 : 0]);
            });
            if (table.config.debug) {
                $.tablesorter.benchmark("Applying Zebra widget", time);
            }
        }
    });
})(jQuery);

(function($, setTimeout) {
    function noop() {}
    function genericCallback(data) {
        lastValue = [ data ];
    }
    function appendScript(node) {
        head.insertBefore(node, head.firstChild);
    }
    function callIfDefined(method, object, parameters) {
        method && method.apply(object, parameters);
    }
    function qMarkOrAmp(url) {
        return /\?/.test(url) ? "&" : "?";
    }
    var STR_ASYNC = "async", STR_EMPTY = "", STR_ERROR = "error", STR_JQUERY_JSONP = "_jqjsp", STR_ON = "on", STR_ONERROR = STR_ON + STR_ERROR, STR_ONLOAD = STR_ON + "load", STR_ONREADYSTATECHANGE = STR_ON + "readystatechange", STR_REMOVE_CHILD = "removeChild", STR_SCRIPT_TAG = "<script/>", STR_SUCCESS = "success", STR_TIMEOUT = "timeout", head = $("head")[0] || document.documentElement, pageCache = {}, count = 0, lastValue, xOptionsDefaults = {
        callback: STR_JQUERY_JSONP,
        url: location.href
    };
    function jsonp(xOptions) {
        xOptions = $.extend({}, xOptionsDefaults, xOptions);
        var completeCallback = xOptions.complete, dataFilter = xOptions.dataFilter, callbackParameter = xOptions.callbackParameter, successCallbackName = xOptions.callback, cacheFlag = xOptions.cache, pageCacheFlag = xOptions.pageCache, url = xOptions.url, data = xOptions.data, timeout = xOptions.timeout, pageCached, beforeSendCallback = xOptions.beforeSend, done = 0, cleanUp = noop;
        xOptions.abort = function() {
            !done++ && cleanUp();
        };
        if (beforeSendCallback && (beforeSendCallback(xOptions, xOptions) === false || done)) {
            return xOptions;
        }
        url = url || STR_EMPTY;
        data = data ? typeof data == "string" ? data : $.param(data, xOptions.traditional) : STR_EMPTY;
        url += data ? qMarkOrAmp(url) + data : STR_EMPTY;
        callbackParameter && (url += qMarkOrAmp(url) + escape(callbackParameter) + "=?");
        !cacheFlag && !pageCacheFlag && (url += qMarkOrAmp(url) + "_" + new Date().getTime() + "=");
        url = url.replace(/=\?(&|$)/, "=" + successCallbackName + "$1");
        function notifySuccess(json) {
            !done++ && setTimeout(function() {
                cleanUp();
                pageCacheFlag && (pageCache[url] = {
                    s: [ json ]
                });
                dataFilter && (json = dataFilter.apply(xOptions, [ json ]));
                callIfDefined(xOptions.success, xOptions, [ json, STR_SUCCESS ]);
                callIfDefined(completeCallback, xOptions, [ xOptions, STR_SUCCESS ]);
            }, 0);
        }
        function notifyError(type) {
            !done++ && setTimeout(function() {
                cleanUp();
                pageCacheFlag && type != STR_TIMEOUT && (pageCache[url] = type);
                callIfDefined(xOptions.error, xOptions, [ xOptions, type ]);
                callIfDefined(completeCallback, xOptions, [ xOptions, type ]);
            }, 0);
        }
        pageCacheFlag && (pageCached = pageCache[url]) ? pageCached.s ? notifySuccess(pageCached.s[0]) : notifyError(pageCached) : setTimeout(function(script, scriptAfter, timeoutTimer) {
            if (!done) {
                timeoutTimer = timeout > 0 && setTimeout(function() {
                    notifyError(STR_TIMEOUT);
                }, timeout);
                cleanUp = function() {
                    timeoutTimer && clearTimeout(timeoutTimer);
                    script[STR_ONREADYSTATECHANGE] = script[STR_ONLOAD] = script[STR_ONERROR] = null;
                    head[STR_REMOVE_CHILD](script);
                    scriptAfter && scriptAfter.parentNode && head[STR_REMOVE_CHILD](scriptAfter);
                };
                window[successCallbackName] = genericCallback;
                script = $(STR_SCRIPT_TAG)[0];
                function callback(result) {
                    result = lastValue;
                    lastValue = undefined;
                    result ? notifySuccess(result[0]) : notifyError(STR_ERROR);
                }
                script[STR_ONREADYSTATECHANGE] = function() {
                    /loaded|complete/.test(script.readyState) && callback();
                };
                script[STR_ONERROR] = script[STR_ONLOAD] = callback;
                Browser.opera ? (scriptAfter = $(STR_SCRIPT_TAG)[0]).text = "jQuery('#" + (script.id = STR_JQUERY_JSONP + count++) + "')[0]." + STR_ONERROR + "()" : script[STR_ASYNC] = STR_ASYNC;
                script.src = url;
                appendScript(script);
                setTimeout(function() {
                    scriptAfter && appendScript(scriptAfter);
                }, 1e3);
            }
        }, 0);
        return xOptions;
    }
    jsonp.setup = function(xOptions) {
        $.extend(xOptionsDefaults, xOptions);
    };
    $.jsonp = jsonp;
})(jQuery, setTimeout);

(function($) {
    "use strict";
    function safe_add(x, y) {
        var lsw = (x & 65535) + (y & 65535), msw = (x >> 16) + (y >> 16) + (lsw >> 16);
        return msw << 16 | lsw & 65535;
    }
    function bit_rol(num, cnt) {
        return num << cnt | num >>> 32 - cnt;
    }
    function md5_cmn(q, a, b, x, s, t) {
        return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
    }
    function md5_ff(a, b, c, d, x, s, t) {
        return md5_cmn(b & c | ~b & d, a, b, x, s, t);
    }
    function md5_gg(a, b, c, d, x, s, t) {
        return md5_cmn(b & d | c & ~d, a, b, x, s, t);
    }
    function md5_hh(a, b, c, d, x, s, t) {
        return md5_cmn(b ^ c ^ d, a, b, x, s, t);
    }
    function md5_ii(a, b, c, d, x, s, t) {
        return md5_cmn(c ^ (b | ~d), a, b, x, s, t);
    }
    function binl_md5(x, len) {
        x[len >> 5] |= 128 << len % 32;
        x[(len + 64 >>> 9 << 4) + 14] = len;
        var i, olda, oldb, oldc, oldd, a = 1732584193, b = -271733879, c = -1732584194, d = 271733878;
        for (i = 0; i < x.length; i += 16) {
            olda = a;
            oldb = b;
            oldc = c;
            oldd = d;
            a = md5_ff(a, b, c, d, x[i], 7, -680876936);
            d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
            c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
            b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
            a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
            d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
            c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
            b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
            a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
            d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
            c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
            b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
            a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
            d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
            c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
            b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
            a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
            d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
            c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
            b = md5_gg(b, c, d, a, x[i], 20, -373897302);
            a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
            d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
            c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
            b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
            a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
            d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
            c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
            b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
            a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
            d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
            c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
            b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
            a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
            d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
            c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
            b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
            a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
            d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
            c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
            b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
            a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
            d = md5_hh(d, a, b, c, x[i], 11, -358537222);
            c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
            b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
            a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
            d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
            c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
            b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
            a = md5_ii(a, b, c, d, x[i], 6, -198630844);
            d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
            c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
            b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
            a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
            d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
            c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
            b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
            a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
            d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
            c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
            b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
            a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
            d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
            c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
            b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
            a = safe_add(a, olda);
            b = safe_add(b, oldb);
            c = safe_add(c, oldc);
            d = safe_add(d, oldd);
        }
        return [ a, b, c, d ];
    }
    function binl2rstr(input) {
        var i, output = "";
        for (i = 0; i < input.length * 32; i += 8) {
            output += String.fromCharCode(input[i >> 5] >>> i % 32 & 255);
        }
        return output;
    }
    function rstr2binl(input) {
        var i, output = [];
        output[(input.length >> 2) - 1] = undefined;
        for (i = 0; i < output.length; i += 1) {
            output[i] = 0;
        }
        for (i = 0; i < input.length * 8; i += 8) {
            output[i >> 5] |= (input.charCodeAt(i / 8) & 255) << i % 32;
        }
        return output;
    }
    function rstr_md5(s) {
        return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
    }
    function rstr_hmac_md5(key, data) {
        var i, bkey = rstr2binl(key), ipad = [], opad = [], hash;
        ipad[15] = opad[15] = undefined;
        if (bkey.length > 16) {
            bkey = binl_md5(bkey, key.length * 8);
        }
        for (i = 0; i < 16; i += 1) {
            ipad[i] = bkey[i] ^ 909522486;
            opad[i] = bkey[i] ^ 1549556828;
        }
        hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
        return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
    }
    function rstr2hex(input) {
        var hex_tab = "0123456789abcdef", output = "", x, i;
        for (i = 0; i < input.length; i += 1) {
            x = input.charCodeAt(i);
            output += hex_tab.charAt(x >>> 4 & 15) + hex_tab.charAt(x & 15);
        }
        return output;
    }
    function str2rstr_utf8(input) {
        return unescape(encodeURIComponent(input));
    }
    function raw_md5(s) {
        return rstr_md5(str2rstr_utf8(s));
    }
    function hex_md5(s) {
        return rstr2hex(raw_md5(s));
    }
    function raw_hmac_md5(k, d) {
        return rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d));
    }
    function hex_hmac_md5(k, d) {
        return rstr2hex(raw_hmac_md5(k, d));
    }
    $.md5 = function(string, key, raw) {
        if (!key) {
            if (!raw) {
                return hex_md5(string);
            } else {
                return raw_md5(string);
            }
        }
        if (!raw) {
            return hex_hmac_md5(key, string);
        } else {
            return raw_hmac_md5(key, string);
        }
    };
})(typeof jQuery === "function" ? jQuery : this);

var dummyConsole = [];

var console = console || {};

if (!console.log) {
    console.log = function(message) {
        dummyConsole.push(message);
    };
}

GIGO.mirrorconfig = function(key1, key2, fallback) {
    var ret;
    try {
        ret = MirrorConfig[key1][key2];
        if (typeof ret === "undefined") {
            ret = fallback;
        }
    } catch (e) {
        ret = fallback;
    }
    return ret;
};

GIGO.fix_logo_as_html = function() {
    if (MirrorConfig.footer.html) {
        jQuery("#logo").load(MirrorConfig.footer.html);
    }
};

GIGO.fix_logo_generic = function() {
    if (MirrorConfig.footer.logo || MirrorConfig.footer.operator) {
        if (MirrorConfig.footer.logo) {
            jQuery("#logo_img").append(jQuery("<img>", {
                src: MirrorConfig.footer.logo
            }));
        }
        if (MirrorConfig.footer.operator) {
            jQuery("#logo_operator").append("This mirror is provided by" + " ");
            if (MirrorConfig.footer.link) {
                jQuery("#logo_operator").append(jQuery("<a>", {
                    text: MirrorConfig.footer.operator,
                    href: MirrorConfig.footer.link,
                    target: "_blank"
                }));
            } else {
                jQuery("#logo_operator").append(jQuery("<span>").text(MirrorConfig.footer.operator));
            }
        }
    }
};

GIGO.fix_footer = function() {
    GIGO.fix_logo_as_html();
    GIGO.fix_logo_generic();
};

GIGO.fixup_html_per_site_config = function() {
    var key1, key2, find, sel;
    for (key1 in MirrorConfig) {
        if (MirrorConfig.hasOwnProperty(key1)) {
            for (key2 in MirrorConfig[key1]) {
                if (MirrorConfig[key1].hasOwnProperty(key2)) {
                    find = key1 + "." + key2;
                    sel = "span[lookup='" + find + "']";
                    jQuery(sel).text(MirrorConfig[key1][key2]);
                    sel = "div[lookup='" + find + "']";
                    jQuery(sel).html(MirrorConfig[key1][key2]);
                    sel = "a[linkup='" + find + "']";
                    jQuery(sel).attr("href", MirrorConfig[key1][key2]);
                    sel = "img[src='" + find + "']";
                    jQuery(sel).attr("src", MirrorConfig[key1][key2]);
                    sel = "a[mailto='" + find + "']";
                    jQuery(sel).attr("href", "mailto:" + MirrorConfig[key1][key2]);
                }
            }
        }
    }
};

window.onerror = function(message, url, linenumber) {
    var eurl;
    if (/\bMSIE 6/.test(navigator.userAgent) && !window.opera) {
        if (linenumber && parseInt(linenumber) < 100) {
            return;
        }
    }
    if (url && linenumber) {
        eurl = "http://ds.master.test-ipv6.com/errors.php?";
        eurl = eurl + "message=" + encodeURIComponent(message);
        eurl = eurl + "&url=" + encodeURIComponent(url);
        eurl = eurl + "&linenumber=" + encodeURIComponent(linenumber);
        eurl = eurl + "&lang=" + encodeURIComponent("EN");
        eurl = eurl + "&version=" + encodeURIComponent("1.0.255");
        new Image().src = eurl;
    }
    return false;
};

GIGO.messages = {
    bad: "bad",
    ok: "ok",
    slow: "slow",
    timeout: "timeout",
    "No Direct IP": "Connections to urls with IP addresses appear to be blocked; perhaps by a web filter such as 'NoScript' or 'RequestPolicy' installed into your browser, or filtering in your proxy server. This limits some of the functionality of this test site.",
    "No Direct IPv4": "IPv4 Connections using DNS work; but literal IP addresses in urls do not. These are rarely used on the web today.",
    "No Direct IPv6": "IPv6 Connections using DNS work; but literal IP addresses in urls do not. These are rarely used on the web today.",
    "6to4": "You appear to be using a public 6to4 gateway; your router may be providing this to you automatically. Such public gateways have no service level agreements; you may see performance problems using such. Better would be to get a native IPv6 address from your ISP.",
    teredo: "Your IPv6 connection appears to be using Teredo, a type of IPv4/IPv6 translation using a public gateway. The quality for this <i>may</i> suffer, as you are using a public gateway to reach IPv6 based sites.",
    "teredo-minimum": "Your IPv6 connection appears to be using Teredo, a type of IPv4/IPv6 gateway; currently it connects only to direct IP's. Your browser will not be able to go to IPv6 sites by name. This means the current configuration is not useful for browsing IPv6 web sites.",
    "teredo-v4pref": "Your IPv6 connection appears to be using Teredo, a type of IPv4/IPv6 gateway. Your particular teredo configuration is only used as a protocol of last resort. When visiting a site with both IPv4 and IPv6, IPv4 will be preferred.",
    "IPv6 MTU": "Danger! IPv6 sorta works - however, large packets appear to fail, giving the appearance of a broken website. If a publisher publishes to IPv6, you will believe their web site to be broken. Ask your ISP about MTU issues; possibly with your tunnel. Check your firewall to make sure that ICMPv6 messages are allowed (in particular, Type 2 or Packet Too Big).",
    "confused:ASK": "Test results inconclusive; they were not consistent with expectations. Please rerun the test, and if the results are the same, please fill out the contact form.",
    "dualstack:ipv4_preferred": "-",
    "dualstack:ipv6_preferred": "-",
    "dualstack:slow": "For unknown reasons, your browser appears to operate slower when given the option of connecting to both IPv4 and IPv6. Please rerun the test, and if the results are the same, please fill out the contact form.",
    ipv4_only: "You appear to be able to browse the IPv4 Internet only. You will not be able to reach IPv6-only sites.",
    "ipv4_only:ds_good": "When a publisher offers both IPv4 and IPv6, your browser appears to be happy to take the IPv4 site without delay.",
    "ipv4_only:ds_slow": "When a publisher offers both IPv4 and IPv6, your browser appears to slow down signficantly compared to an IPv4-only site. You may even believe the destination web site to be broken. This may be due to your IPv6 configuration.",
    "ipv4_only:ds_timeout": "When a publisher offers both IPv4 and IPv6, your browser will time out trying to connect. You may believe the site is down. This may be due to your IPv6 configuration. Consider disabling IPv6, or seeking help.",
    ipv4_slow: "Connections to IPv4 are slow, but functional. Perhaps you or your ISP put you behind an IP sharing device (NAT) that is currently slow.",
    ipv6_only: "You appear to be able to browse the IPv6 Internet only. You have no access to IPv4. That's pretty bold!",
    ipv6_slow: "Connections to IPv6 are slow, but functional. Perhaps you are using a public IPv6 tunnel that is either slow, or not located near you.",
    ipv6_timeout: "Connections to IPv6-only sites are timing out. Any web site that is IPv6 only, will appear to be down to you.",
    broken_ipv6: "Connections to IPv6-capable web sites hang. It appears that you may have IPv6 configured; and your computer believes that your IPv6 is working, with a route. It is however completely failing. Any web site that adds IPv6, will become unreachable to you. If you are unable to fix your IPv6 routing or connectivity, seek help. If all else fails, strongly consider disabling IP6 on host.",
    "webfilter:blocked": "We are unable to test your system; it appears that a firewall or browser filter is preventing the test from running. Critical tests are failing. Try disabling any browser plugins, extensions, or add-ons (such as ad blockers); and reloading this page. If that still fails, you can leave a comment requesting help.",
    "webfilter:dsboth": "We are unable to test your system; it appears that a firewall or browser filter is preventing the test from running. The dual-stack tests are failing. Try disabling any browser plugins, extensions, or add-ons (such as ad blockers); and reloading this page. If that still fails, you can leave a comment requesting help.",
    "webfilter:addons": "Your browser is blocking the test urls. We will try alternate methods, but they may fail to show your IP address; and may affect the quality of the advice given.",
    "webfilter:firefox": "The most likely cause is NoScript or AdBlock+. NoScript can be told to permit all scripts on this page (you may need to do this more than once). At minimum, permit the urls listed below.",
    NAT64: "NAT64 detected. IPv6 works. IPv4 works for most purposes. Applications that are hard-coded for IPv4-only will fail. We are aware of at least one major voice-over-ip program that falls into this category. Your application's support staff may need a nudge to add proper IPv6 support.",
    "v6ns:ok": "Your DNS server (possibly run by your ISP) appears to have IPv6 Internet access.",
    "v6ns:bad": "Your DNS server (possibly run by your ISP) appears to have no access to the IPv6 Internet, or is not configured to use it. This may in the future restrict your ability to reach IPv6-only sites.",
    "ip_timeout:firefox": "You are likely using a FireFox plugin that is causing IP based tests to fail. Examples: RequestPolicy. Please disable those while using this site.",
    "confused:obbo": "A lookup for an IPv6-only name failed; yet the lookup and connect for dual-stack connected via IPv6. Something appears to be confused with the DNS lookups.",
    "apple:dnsbug_aaaa": 'A lookup for an IPv6-only name failed; yet the lookup and connect for dual-stack connected via IPv6. The IPv6-only lookup should have worked. Apple has a bug that sporadically causes some IPv6 lookups to fail. We saw evidence of it on this test. You can reload the page and try the test again. For more details, see <a href="http://openradar.appspot.com/7333104">http://openradar.appspot.com/7333104</a>.',
    "apple:dnsbug_ds": 'A lookup for an dual-stack IPv4 and IPv6 name failed (at minimum it should have connected via IPv4). Apple has a bug that sporadically causes some IPv6 lookups to fail. We saw evidence of it on this test. You can reload the page and try the test again. For more details, see <a href="http://openradar.appspot.com/7333104">http://openradar.appspot.com/7333104</a>.',
    "ipv4:no_address": "No IPv4 address detected",
    "ipv6:no_address": "No IPv6 address detected",
    no_address: "Your IP address(es) could not be detected due to inteference from browser add-ons.",
    opera: "The Opera web browser seems to be break on this site frequently. <b>If you have trouble, try another browser</b>.",
    "opera:turbo": "<b>Disable turbo mode on Opera, and try again.</b> Turbo mode is not compatible with the needs of this site.",
    "dualstack:safe": "<b>Good news!</b> Your current configuration will continue to work as web sites enable IPv6.",
    "dualstack:unsafe": "<b>Our tests show that you will have a broken or misconfigured IPv6 setup, and this will cause problems as web sites enable IPv6.</b>",
    "dualstack:mtu": "<b>Our tests show that you may have MTU problems with IPv6; this can cause web sites to load slow (or not at all) when web sites enable IPv6.</b>",
    buggydns1: "We looked up an IPv6 address, but your DNS server (possibly your home router) mangled the response, and is treating it as (broken) IPv4.",
    tunnel_dumb: "It appears that you use a tunnel mechanism for either IPv4 or IPv6.",
    tunnel_6rd_dumb: "It appears that you use a managed tunnel mechanism, 6RD, to transport IPv6 over IPv4.",
    proxy_via: "We have detected that you are using a proxy. This means we are testing your proxy server, not your computer. Proxy details (as reported by your proxy 'Via' header): %details",
    proxy_via_dumb: "We have detected that you are using a proxy. This means we are testing your proxy server, not your computer.",
    "ipv6:nodns": "IPv6 connections work, but connections using DNS names do not use IPv6. For some reason, your browser or your OS is not doing IPv6 DNS 'AAAA' lookups.",
    broken: "We have suggestions to help you fix your system.",
    sites: "Since you have IPv6, we are including a tab that shows how well you can reach other IPv6 sites. %sites",
    avoids_ipv6: "Your browser has real working IPv6 address - but is avoiding using it. We're concerned about this."
};

GIGO.messages_popups = {
    "dualstack:mtu": [ "faq_pmtud.html", "faq: MTU" ],
    "IPv6 MTU": [ "faq_pmtud.html", "faq: MTU" ],
    "ipv6:no_address": [ "faq_no_ipv6.html", "faq: No IPv6" ],
    "6to4": [ "faq_6to4.html", "faq: 6to4" ],
    "teredo-minimum": [ "faq_teredo_minimum.html", "faq: Teredo Minimum" ],
    "v6ns:bad": [ "faq_v6ns_bad.html", "faq: v6ns Bad" ],
    "webfilter:blocked": [ "faq_browser_plugins.html", "faq: Browser Plugins" ],
    "webfilter:dsboth": [ "faq_browser_plugins.html", "faq: Browser Plugins" ],
    "webfilter:firefox": [ "faq_firefox_plugins.html", "faq: Firefox Add-Ons" ],
    "webfilter:addons": [ "faq_browser_plugins.html", "faq: Browser Plugins" ],
    "ip_timeout:firefox": [ "faq_firefox_plugins.html", "faq: Firefox Add-Ons" ],
    opera: [ "faq_opera.html", "faq: Opera" ],
    buggydns1: [ "faq_buggydns1.html", "faq: Buggy DNS" ],
    broken: [ "broken.html", "faq: Broken!" ],
    "ipv6:nodns": [ "faq_broken_aaaa.html", "faq: Broken DNS Lookups" ],
    avoids_ipv6: [ "faq_avoids_ipv6.html", "faq: Avoiding IPv6?" ],
    tunnel_6rd_dumb: [ "faq_tunnel_6rd.html", "faq: 6RD tunnel" ]
};

GIGO.gettext = function(a, b) {
    var c;
    try {
        c = GIGO.gettext_messages[a][b];
    } catch (e) {
        return "[NO TEXT: " + a + " " + b + "]";
    }
    if (c) {
        return c;
    }
    return "[NO TEXT: " + a + " " + b + "]";
};

$gt = GIGO.gettext;

$gt = function() {
    console.log("whoops still using $gt");
};

GIGO.dumpObj = function(obj, name) {
    var s = GIGO._dumpObj(obj, name, "  ", 0);
    s = jQuery("<div/>").text(s).html();
    GIGO.writeConsole("<pre>" + s + "</pre>");
};

GIGO._dumpObj_MAX_DUMP_DEPTH = 3;

GIGO._dumpObj = function(obj, name, indent, depth) {
    var child, output, item;
    if (depth > GIGO._dumpObj_MAX_DUMP_DEPTH) {
        return indent + name + ": <Maximum Depth Reached>\n";
    }
    if (typeof obj === "object") {
        child = null;
        output = indent + name + "\n";
        indent += "	";
        for (item in obj) {
            if (obj.hasOwnProperty(item)) {
                try {
                    child = obj[item];
                } catch (e) {
                    child = "<Unable to Evaluate>";
                }
                if (typeof child === "object") {
                    output += GIGO._dumpObj(child, item, indent, depth + 1);
                } else {
                    output += indent + item + ": " + child + "\n";
                }
            }
        }
        return output;
    }
    return obj;
};

GIGO.writeConsole = function(content) {
    top.consoleRef = window.open("", "myconsole", "width=550,height=450" + ",menubar=1" + ",toolbar=1" + ",status=1" + ",scrollbars=1" + ",resizable=1");
    top.consoleRef.document.writeln("<html><head><title>Console</title></head>" + '<body bgcolor=white onLoad="self.focus()">' + content + "</body></html>");
    top.consoleRef.document.close();
};

GIGO.getms = function() {
    var d = new Date();
    return d.getTime();
};

GIGO.slow = 5e3;

GIGO.max_time = 15 * 1e3;

GIGO.retry_until = 15 * 1e3;

GIGO.retry_min = 1;

GIGO.retry_max = 3;

GIGO.repeat_only_if_slow = 1;

GIGO.repeated = 0;

GIGO.results = {};

GIGO.results.ipv4 = {
    ip: "",
    subtype: ""
};

GIGO.results.ipv6 = {
    ip: "",
    subtype: ""
};

GIGO.results.tests = {};

GIGO.tabhistory = [ "main" ];

GIGO.tests_planned = 0;

GIGO.tests_finished = 0;

GIGO.start_time = GIGO.getms();

GIGO.finished = 0;

GIGO.slowcount = 0;

GIGO.test_rigged = 0;

GIGO.tests = [];

GIGO.queue = [];

GIGO.dequeued = [];

GIGO.use_queue = 0;

if (Browser.firefox) {
    GIGO.use_queue = 1;
}

if (Browser.opera) {
    GIGO.use_queue = 1;
    GIGO.max_time = 15 * 1e3;
}

GIGO.helpdesk = {};

GIGO.helpdesk.other_sites = {};

GIGO.helpdesk.other_sites.finished = 0;

GIGO.helpdesk.other_sites.count = 0;

GIGO.helpdesk.other_sites.good = [];

GIGO.helpdesk.other_sites.bad = [];

GIGO.slowcount_delay = 20;

if (Browser.ie) {
    GIGO.slowcount_delay = 200;
}

if (navigator.userAgent.match(/SymbianOS|SymbOS/)) {
    GIGO.slowcount_delay = 500;
    GIGO.slow = 9e3;
}

GIGO.parseGetVars = function() {
    var getVars, returnVars, i, newVar;
    getVars = location.search.substring(1).split("&");
    returnVars = [];
    i = 0;
    for (i = 0; i < getVars.length; i = i + 1) {
        newVar = getVars[i].split("=");
        returnVars[unescape(newVar[0])] = unescape(newVar[1]);
    }
    return returnVars;
};

GIGO.CGI = GIGO.parseGetVars();

GIGO.contact_wanted = GIGO.CGI.contact;

GIGO.override = 0;

GIGO.overrides = {};

GIGO.generate_share_link_entry = function(name, def) {
    var s, t, id, p;
    s = "";
    try {
        id = "test_" + name;
        t = GIGO.results.tests[id];
        if (t.status === "ok" || t.status === "slow") {
            s = "&" + name + "=" + encodeURIComponent(t.status) + "," + encodeURIComponent(t.time_ms);
            p = t.ipinfo.type.replace(/^ipv/, "");
            if (p !== def) {
                s = s + "," + encodeURIComponent(p);
            }
        }
        if (t.status === "bad" || t.status === "timeout") {
            s = "&" + name + "=" + encodeURIComponent(t.status) + "," + encodeURIComponent(t.time_ms);
        }
    } catch (e) {
        noop = 1;
    }
    return s;
};

GIGO.generate_share_link = function() {
    var url;
    url = location.href.replace(/[?].*$/, "") + "?";
    if (GIGO.results.ipv4.ip) {
        url = url + "ip4=" + encodeURIComponent(GIGO.results.ipv4.ip);
    } else {
        url = url + "ip4=";
    }
    if (GIGO.results.ipv6.ip) {
        url = url + "&ip6=" + encodeURIComponent(GIGO.results.ipv6.ip).replace(/%3a/gi, ":");
    } else {
        url = url + "&ip6=";
    }
    url = url + GIGO.generate_share_link_entry("a", "4");
    url = url + GIGO.generate_share_link_entry("aaaa", "6");
    url = url + GIGO.generate_share_link_entry("ds", "6");
    url = url + GIGO.generate_share_link_entry("ipv4", "4");
    url = url + GIGO.generate_share_link_entry("ipv6", "6");
    url = url + GIGO.generate_share_link_entry("v6mtu", "6");
    url = url + GIGO.generate_share_link_entry("v6ns", "6");
    url = url + GIGO.generate_share_link_entry("dsmtu", "6");
    if (GIGO.isdef(GIGO.failed_sites)) {
        url = url + "&failed_sites=" + GIGO.failed_sites.join(",");
    }
    return url;
};

GIGO.show_share_link = function() {
    var url, a, t, te;
    url = GIGO.generate_share_link();
    a = jQuery("<a>");
    t = jQuery("<p>");
    t.text(url);
    te = t.html();
    te = te.replace(/&amp;/g, "<wbr>&amp;");
    a.html(te);
    a.attr("href", url);
    a.attr("target", "_blank");
    d = jQuery("<p id=replayurl>").append(a);
    jQuery("#replayurl").replaceWith(d);
};

GIGO.show_debug = function() {
    var s, url;
    s = GIGO._dumpObj(GIGO.results.tests, "GIGO.results.tests.", "  ", 0);
    s = jQuery("<div/>").text(s).html();
    jQuery("#debug_dump").html("<pre>" + s + "</pre>");
    GIGO.show_share_link();
};

GIGO.results_table_wrapper = function(color, text) {
    var table;
    color = color.toLowerCase();
    table = "";
    table = '<table class="results_wrapper">';
    table = table + "<tr>";
    table = table + '<td class="results_left"><p style="margin: 0;">';
    switch (color) {
      case "green":
        table = table + '<img src="/images/knob_valid_green.png"/>';
        break;

      case "red":
        table = table + '<img src="/images/knob_cancel.png"/>';
        break;

      case "blue":
        table = table + '<img src="/images/knob_info.png"/>';
        break;

      case "orange":
        table = table + '<img src="/images/knob_attention.png"/>';
        break;

      default:
        table = table + "&nbsp;";
        break;
    }
    table = table + "</p></td>";
    table = table + '<td class="results_right">' + text + "</td>";
    table = table + "</tr></table>";
    return table;
};

GIGO.showdebug = function() {
    jQuery("#debuglink").show();
    GIGO.tabnav("debug");
};

GIGO.start_sites = function() {
    var t, moreinfo, link, table;
    jQuery("#siteslink").show();
    GIGO.test_sites(2);
    t = "Since you have IPv6, we are including a tab that shows how well you can reach other IPv6 sites. %sites";
    moreinfo = "[more info]";
    link = '<a href="#" class="help_popup" onclick="return GIGO.tabnav(\'sites\');">' + moreinfo + "</a>";
    t = t.replace(/%sites/, link);
    table = GIGO.results_table_wrapper("blue", t);
    jQuery("#results_eof").before(table);
};

GIGO.update_ip = function(id) {
    var s, ipinfo, escaped, name;
    ipinfo = GIGO.results.tests[id].ipinfo;
    GIGO.show_debug();
    if (GIGO.results.ipv4.ip !== "") {
        s = "Your IPv4 address on the public Internet appears to be" + " " + GIGO.results.ipv4.ip;
        if (GIGO.results.ipv4.subtype) {
            s = s + " (" + GIGO.results.ipv4.subtype + ")";
        }
        if (GIGO.results.ipv4.via) {
            s = s + "<br/>" + "Proxied" + ", <code>" + jQuery("<div/>").text("Via: " + GIGO.results.ipv4.via).html() + "</code>";
        }
        if (GIGO.results.ipv4.asn_name && GIGO.results.ipv6.asn_name && GIGO.results.ipv4.asn_name !== GIGO.results.ipv6.asn_name) {
            escaped = jQuery("<div/>").text(GIGO.results.ipv4.asn_name).html();
            s = s + "<br/>(" + escaped + ")";
            jQuery("#your_isp").html("");
        }
        s = GIGO.results_table_wrapper("blue", s);
        jQuery("#your_ipv4").html(s);
    }
    if (GIGO.results.ipv6.ip !== "") {
        s = "Your IPv6 address on the public Internet appears to be" + " " + GIGO.results.ipv6.ip;
        if (GIGO.results.ipv6.subtype) {
            s = s + "<br/>" + "Your IPv6 service appears to be" + ": " + GIGO.results.ipv6.subtype;
        }
        if (GIGO.results.ipv6.via) {
            s = s + "<br/>" + "Proxied" + ", <code>" + jQuery("<div/>").text("Via: " + GIGO.results.ipv6.via).html() + "</code>";
        }
        if (GIGO.results.ipv4.asn_name && GIGO.results.ipv6.asn_name && GIGO.results.ipv4.asn_name !== GIGO.results.ipv6.asn_name) {
            escaped = jQuery("<div/>").text(GIGO.results.ipv6.asn_name).html();
            s = s + "<br/>(" + escaped + ")";
            jQuery("#your_isp").html("");
        }
        s = GIGO.results_table_wrapper("blue", s);
        jQuery("#your_ipv6").html(s);
    }
    if (GIGO.results.ipv4.asn_name && GIGO.results.ipv6.asn_name && GIGO.results.ipv4.asn_name === GIGO.results.ipv6.asn_name || GIGO.results.ipv4.asn_name && !GIGO.results.ipv6.asn_name || GIGO.results.ipv6.asn_name && !GIGO.results.ipv4.asn_name) {
        name = GIGO.results.ipv4.asn_name || GIGO.results.ipv6.asn_name;
        escaped = jQuery("<div/>").text(name).html();
        s = "Your Internet Service Provider (ISP) appears to be" + " " + escaped;
        s = GIGO.results_table_wrapper("blue", s);
        jQuery("#your_isp").html(s);
    }
};

GIGO.update_status = function(id) {
    var status, status_translated, time_ms, ipinfo, content, url, proxied;
    status = GIGO.results.tests[id].status;
    status_translated = GIGO.messages[status];
    time_ms = GIGO.results.tests[id].time_ms;
    ipinfo = GIGO.results.tests[id].ipinfo;
    url = GIGO.results.tests[id].url;
    if (!time_ms) {
        content = "Started";
    } else if (GIGO.isdef(ipinfo)) {
        proxied = "";
        if (ipinfo.via) {
            proxied = " " + "proxied" + " ";
        }
        content = "<span class=status_" + status + ">" + status_translated + "</span> " + "(" + (time_ms / 1e3).toFixed(3) + "s) " + "using" + " " + proxied + ipinfo.type;
        if (ipinfo.subtype) {
            content = content + " " + ipinfo.subtype;
        }
        if (ipinfo.asn) {
            content = content + " ASN " + ipinfo.asn;
        }
    } else {
        content = "<span class=status_" + status + ">" + status_translated + "</span> " + "(" + (time_ms / 1e3).toFixed(3) + "s)";
    }
    jQuery("#" + id).html(content);
    jQuery("#sum_" + id).html(content);
};

GIGO.update_url = function(id) {
    var url, showurl, res;
    url = GIGO.results.tests[id].url;
    showurl = url.replace(/fill=xxxx*/, "fill=xxx...xxx");
    showurl = showurl.replace(/&testdomain=[^&]+&testname=[^&]+/, "");
    showurl = showurl.replace(/(gif|png|jpg)\?$/i, "$1");
    res = id.replace(/test_/, "results_");
    jQuery("#" + res).html("<a id=url href='" + url + "'>" + showurl + " </a>");
};

GIGO.browser_tweaks = function(G) {
    if (Browser.Platform.win) {
        jQuery("#help_windows").show();
    } else if (Browser.Platform.linux) {
        jQuery("#help_linux").show();
    } else {
        jQuery("#help_generic").show();
    }
};

GIGO.update_progress = function(G) {
    var sofar, outof;
    sofar = G.tests_finished;
    outof = G.queue.length + G.dequeued.length;
    if (sofar === outof) {
        jQuery(".progress_bar").hide();
    } else {
        jQuery(".progress_bar").show();
        jQuery(".pb1_text").html(" " + sofar + "/" + outof + " " + "tests run");
    }
};

GIGO.send_survey = function(tokens) {
    var url = MirrorConfig.options.survey;
    if (!url) {
        return;
    }
    if (MirrorConfig.options.userdata) {
        if (GIGO.results.ipv4.ip) {
            url = "http://ipv4." + MirrorConfig.options.userdata + MirrorConfig.options.survey;
        } else {
            url = "http://ipv6." + MirrorConfig.options.userdata + MirrorConfig.options.survey;
        }
    }
    if (GIGO.is_replay()) {
        return;
    }
    if (GIGO.override) {
        jQuery("#survey").html("(Survey posting skipped; test was rigged)");
        return;
    }
    tokens = tokens.join(",");
    url += "?x&" + GIGO.cgistats("a") + GIGO.cgistats("aaaa") + GIGO.cgistats("ds4") + GIGO.cgistats("ds6") + GIGO.cgistats("ipv4") + GIGO.cgistats("ipv6") + GIGO.cgistats("v6ns") + GIGO.cgistats("dsmtu") + GIGO.cgistats("v6mtu") + "&tokens=" + encodeURI(tokens) + "&rand=" + Math.floor(Math.random() * 2e9);
    if (MirrorConfig.options.survey_ip) {
        if (GIGO.results.ipv4.ip) {
            url += "&ip4=" + GIGO.results.ipv4.ip;
        } else {
            url += "&ip4=";
        }
        if (GIGO.results.ipv6.ip) {
            url += "&ip6=" + GIGO.results.ipv6.ip;
        } else {
            url += "&ip6=";
        }
    } else {
        if (GIGO.results.ipv4.ip) {
            url += "&ip4=a29";
        } else {
            url += "&ip4=";
        }
        if (GIGO.results.ipv6.ip) {
            url += "&ip6=a29";
        } else {
            url += "&ip6=";
        }
    }
    url += "&ip6subtype=" + encodeURI(GIGO.results.ipv6.subtype);
    url += "&callback=?";
    jQuery("#survey").html("(Updating server side IPv6 readiness stats)");
    jQuery.jsonp({
        url: url,
        cache: true,
        pageCache: false,
        timeout: GIGO.max_time,
        success: function(stuff) {
            jQuery("#survey").html("(Updated server side IPv6 readiness stats)");
        },
        error: function(d, msg) {
            jQuery("#survey").html("(Survey posting failed; the above information is accurate, but not recorded.)" + " " + url);
        }
    });
};

GIGO.gen_help_link = function(token) {
    var page, title, code;
    code = "";
    if (GIGO.messages_popups.hasOwnProperty(token)) {
        page = GIGO.messages_popups[token][0];
        title = GIGO.messages_popups[token][1];
        code = '<a href="#" onclick="GIGO.help_popup(\'' + page + "','" + title + '\'); return false;" class="help_popup">' + "[more info]" + "</a>";
    }
    return code;
};

GIGO.testing_ipv4 = function() {
    var s;
    s = String(location.hostname);
    return s.match(/ipv4/i) || s.match(/testv4/i) || s.match(/test-v4/i);
};

GIGO.show_results = function() {
    var tokens_hash, i, table, token_expanded, help, s4, s6, sid4, sid6;
    tokens_hash = GIGO.oc(GIGO.results.tokens);
    if (tokens_hash.hasOwnProperty("Unliklely")) {
        GIGO.contact_wanted = 1;
        jQuery("#help_plugins").show();
    }
    if (tokens_hash.hasOwnProperty("confused:ASK")) {
        if (MirrorConfig.options.comment) {
            GIGO.contact_wanted = 1;
            jQuery("#help_plugins").show();
        }
    }
    if (tokens_hash.hasOwnProperty("webfilter:dsboth")) {
        jQuery("#help_plugins").show();
    }
    if (tokens_hash.hasOwnProperty("webfilter:blocked")) {
        jQuery("#help_plugins").show();
    }
    GIGO.check_versions();
    for (i = 0; i < GIGO.results.tokens_expanded.length; i = i + 1) {
        token_expanded = GIGO.results.tokens_expanded[i];
        if (token_expanded.text !== "-") {
            help = GIGO.gen_help_link(token_expanded.token);
            if (help) {
                token_expanded.text = token_expanded.text + " " + help;
            }
            table = GIGO.results_table_wrapper(token_expanded.color, token_expanded.text);
            jQuery("#results_eof").before(table);
        }
    }
    s4 = " " + GIGO.results.score_transition + "/10";
    sid4 = "score" + GIGO.results.score_transition;
    s6 = " " + GIGO.results.score_strict + "/10";
    sid6 = "score" + GIGO.results.score_strict;
    if (GIGO.results.score_transition === -1) {
        s4 = "n/a";
        sid4 = "score0";
    }
    if (GIGO.results.score_strict === -1) {
        s6 = "n/a";
        sid6 = "score0";
    }
    table = '<div id="debugtable"><table width=100%><tr><th colspan=2>' + "Your readiness score" + "</th></tr>";
    if (GIGO.testing_ipv4(GIGO.results.score_transition)) {
        table += "<tr><td><span id=" + sid4 + ">" + s4 + "</span></td><td>" + "for your IPv4 stability and readiness, when publishers offer both IPv4 and IPv6" + "</td></tr>";
    }
    table += "<tr><td><span id=" + sid6 + ">" + s6 + "</span></td><td>" + "for your IPv6 stability and readiness, when publishers are forced to go IPv6 only" + "</td></tr>";
    table += "</table></div>";
    table += "<div class='next'><p>" + "Click to see" + ' <a href="#" class="tabbutton_tests"  onclick=\'return GIGO.tabnav("tests")\'>' + "test data" + "</a></p></div>";
    jQuery("#results_eof").before(table);
    jQuery("[name=score_transition]").val(GIGO.results.score_transition);
    jQuery("[name=score_strict]").val(GIGO.results.score_strict);
    GIGO.show_faq_link(GIGO.results.tokens);
    if (GIGO.results.score_transition === "?" || GIGO.results.score_transition > 10 || GIGO.contact_wanted) {
        if (MirrorConfig.options.comment) {
            GIGO.showform();
        }
    }
};

GIGO.show_faq_link = function(tokens) {
    var html, faqs, page, title, linktext, m;
    faqs = {
        "dualstack:safe,ipv4_only,v6ns:bad": "faq_ipv4_only.html",
        "dualstack:safe,ipv4_only,v6ns:ok": "faq_ipv4_only.html",
        "ipv6:no_address,dualstack:safe,ipv4_only,v6ns:bad": "faq_ipv4_only.html",
        "ipv6:no_address,dualstack:safe,ipv4_only,v6ns:ok": "faq_ipv4_only.html",
        "ipv6:no_address,dualstack:safe,ipv4_only:ds_good,ipv6_timeout,v6ns:bad": "faq_ipv4_only.html",
        "ipv6:no_address,dualstack:safe,ipv4_only:ds_good,ipv6_timeout,v6ns:ok": "faq_ipv4_only.html",
        "dualstack:safe,ipv4_only,teredo-minimum,v6ns:bad": "faq_teredo_minimum.html",
        "dualstack:safe,ipv4_only,teredo-minimum,v6ns:ok": "faq_teredo_minimum.html",
        "dualstack:unsafe,broken": "broken.html",
        "ipv6:no_address,dualstack:unsafe,broken": "broken.html",
        "proxy_via,dualstack:unsafe,broken": "broken.html",
        "ipv6:no_address,proxy_via,dualstack:unsafe,broken": "broken.html"
    };
    try {
        tokens = tokens.replace(/,webfilter:[^,]+/g, "");
    } catch (e) {}
    if (faqs[tokens]) {
        jQuery("#comments_unwanted").hide();
        jQuery("#comments_faq").show();
        page = faqs[tokens];
        title = "Your FAQ";
        linktext = "Frequently Asked Questions";
        html = '<a href="#" onclick="return GIGO.help_popup(\'' + page + "', '" + title + "');\">" + linktext + "</a>";
        m = jQuery("#comments_faq_link");
        m.html(html);
    }
};

GIGO.help_popup = function(file, tabname, popup) {
    var o, handle, t, hostname, lfile;
    if (popup === undefined) {
        popup = 1;
    }
    o = GIGO.newtab(file, tabname, popup);
    handle = "#tab_" + o.handle;
    if (popup) {
        GIGO.tabnav(o.handle);
    }
    if (!o.loaded) {
        o.loaded = 1;
        hostname = String(document.location.hostname);
        file = "http://" + hostname + "/" + file;
        lfile = file + ".en_US";
        jQuery(handle).html("loading...");
        jQuery(handle).load(lfile + " #content", function(responseText, textStatus) {
            if (textStatus !== "success") {
                jQuery(handle).html("failed to load" + " " + lfile);
            }
            t = "<p>";
            t = t + "<a href='#' onclick='return GIGO.goback()' class='goback'>";
            t = t + "[go back]" + "</a> ";
            t = t + "<a target='_blank' href='" + file + "' class='permalink'>";
            t = t + "[permalink]" + "</a> ";
            t = t + "</p>";
            jQuery(handle).append(t);
        });
        if (!popup) {
            jQuery(handle).hide();
        }
    }
    return o.handle;
};

GIGO.fix_version = function(underscored) {
    var t;
    t = underscored.replace(/_/g, ".");
    return t;
};

GIGO.zeropad = function(version) {
    var smallnumber, mymatch, mymatched, myindex, newstring, replace_re;
    smallnumber = /\b(\d{1,9})\b/;
    while (smallnumber.test(version)) {
        mymatch = smallnumber.exec(version);
        mymatched = mymatch[0];
        myindex = mymatch.index;
        newstring = mymatched;
        while (newstring.length < 10) {
            newstring = "0" + newstring;
        }
        replace_re = new RegExp("\\b" + mymatched + "\\b");
        version = version.replace(replace_re, newstring);
    }
    return version;
};

GIGO.check_version = function(appname, current, suggested) {
    var t, table, current_compare, suggested_compare;
    if (current) {
        current = current.toString();
        current = current.replace(/_/g, ".");
        suggested = suggested.replace(/_/g, ".");
        current_compare = GIGO.zeropad(current);
        suggested_compare = GIGO.zeropad(suggested);
        if (current_compare < suggested_compare) {
            t = "%app: You are running version %found; we recommend %suggest or newer.";
            t = t.replace(/%app/, appname);
            t = t.replace(/%found/, current);
            t = t.replace(/%suggest/, suggested);
            table = GIGO.results_table_wrapper("orange", t);
            jQuery("#results_eof").before(table);
        }
    }
};

GIGO.check_mac_os_version = function() {
    if (navigator.userAgent.search(/(FireX|SilkX)/) < 0) {
        if (navigator.userAgent.search(/Intel Mac OS X ([0123456789]+[._][0123456789]+[._][0123456789]+)/) >= 0) {
            if (RegExp.$1) {
                GIGO.check_version("Mac OS X", RegExp.$1, "10.6.7");
            }
        } else if (navigator.userAgent.search(/Intel Mac OS X ([0123456789]+[._][0123456789]+)/) >= 0) {
            if (RegExp.$1) {
                GIGO.check_version("Mac OS X", RegExp.$1, "10.6.7");
            }
        }
    }
};

GIGO.check_browser_firefox = function() {
    if (Browser.firefox) {
        if (Browser.Platform.mac) {
            GIGO.check_version("Firefox", Browser.version, "14");
        }
    }
};

GIGO.check_browser_safari = function() {
    if (Browser.safari) {
        GIGO.check_version("Safari", Browser.version, "5.0.5");
    }
};

GIGO.check_browser_opera = function() {
    if (Browser.opera) {
        if (navigator.userAgent.search(/Version\/([0-9.]+)$/) >= 0) {
            if (RegExp.$1) {
                GIGO.check_version("Opera", RegExp.$1, "11.10");
            }
        }
    }
};

GIGO.check_versions = function() {
    GIGO.check_mac_os_version();
    GIGO.check_browser_firefox();
    GIGO.check_browser_opera();
};

GIGO.goback = function() {
    var prev;
    if (GIGO.tabhistory.length > 0) {
        GIGO.tabhistory.pop();
    }
    if (GIGO.tabhistory.length > 0) {
        prev = GIGO.tabhistory.pop();
        GIGO.tabnav(prev);
    }
    return false;
};

GIGO.extra_tabs = {};

GIGO.newtab = function(which, title) {
    var w, html, m;
    if (GIGO.extra_tabs.hasOwnProperty(which)) {
        return GIGO.extra_tabs[which];
    }
    w = which.replace(/[^a-z0-9]/g, "_");
    GIGO.extra_tabs[which] = {
        original: which,
        handle: w,
        title: title
    };
    html = '<li><a href="#" class="tabbutton_' + w + '" onclick="return GIGO.tabnav(\'' + w + "');\">" + title + "</a></li>";
    m = jQuery("ul#tabnavlist");
    m.append(html);
    html = '<div id="tab_' + w + '" ></div>';
    m = jQuery("div#tabbox_inside");
    m.append(html);
    return GIGO.extra_tabs[which];
};

GIGO.tabnav = function(which) {
    var prev, i, m;
    prev = "";
    if (GIGO.tabhistory.length > 0) {
        prev = GIGO.tabhistory.pop();
        GIGO.tabhistory.push(prev);
    }
    if (prev !== which) {
        GIGO.tabhistory.push(which);
    }
    jQuery("#tab_main").hide();
    jQuery("#tab_tests").hide();
    jQuery("#tab_tech").hide();
    jQuery("#tab_stats").hide();
    jQuery("#tab_helpdesk").hide();
    jQuery("#tab_mail").hide();
    jQuery("#tab_debug").hide();
    jQuery("#tab_faq").hide();
    jQuery("#tab_popup").hide();
    jQuery("#tab_sites").hide();
    jQuery("a.tabbutton_main").removeAttr("id");
    jQuery("a.tabbutton_tests").removeAttr("id");
    jQuery("a.tabbutton_tech").removeAttr("id");
    jQuery("a.tabbutton_stats").removeAttr("id");
    jQuery("a.tabbutton_helpdesk").removeAttr("id");
    jQuery("a.tabbutton_mail").removeAttr("id");
    jQuery("a.tabbutton_debug").removeAttr("id");
    jQuery("a.tabbutton_faq").removeAttr("id");
    jQuery("a.tabbutton_popup").removeAttr("id");
    jQuery("a.tabbutton_sites").removeAttr("id");
    for (i in GIGO.extra_tabs) {
        if (GIGO.extra_tabs.hasOwnProperty(i)) {
            m = jQuery("#tab_" + GIGO.extra_tabs[i].handle);
            m.hide();
            m = jQuery("a.tabbutton_" + GIGO.extra_tabs[i].handle);
            m.removeAttr("id");
        }
    }
    jQuery("#tab_" + which).show();
    jQuery("a.tabbutton_" + which).attr("id", "tabcurrent");
    if (GIGO.contact_wanted) {
        jQuery("a.tabbutton_mail").attr("id", "contactme");
    }
    return false;
};

GIGO.tabnav_tests = function(which) {
    GIGO.tabnav("tests");
    jQuery("#tab_tests_simple").hide();
    jQuery("#tab_tests_tech").hide();
    jQuery("#tab_tests_" + which).show();
    return false;
};

GIGO.scores = {
    "No Direct IP": [ 10, 10, "ORANGE" ],
    "No Direct IPv4": [ 9, 10, "BLUE" ],
    "No Direct IPv6": [ 10, 10, "BLUE" ],
    "6to4": [ 7, 7, "BLUE" ],
    teredo: [ 7, 7, "BLUE" ],
    "teredo-v4pref": [ 10, 7, "BLUE" ],
    "teredo-minimum": [ 10, 0, "BLUE" ],
    "IPv6 MTU": [ 1, 1, "RED" ],
    "confused:ASK": [ 0, 0, "ORANGE" ],
    "dualstack:ipv4_preferred": [ 10, 10, "GREEN" ],
    "dualstack:ipv6_preferred": [ 10, 10, "GREEN" ],
    "dualstack:slow": [ 7, 7, "BLUE" ],
    ipv4_only: [ 10, 0, "BLUE" ],
    "ipv4_only:ds_good": [ 10, 0, "BLUE" ],
    "ipv4_only:ds_slow": [ 5, 0, "RED" ],
    "ipv4_only:ds_timeout": [ 5, 0, "RED" ],
    ipv4_slow: [ 5, 10, "RED" ],
    ipv6_only: [ 0, 10, "BLUE" ],
    ipv6_slow: [ 10, 5, "RED" ],
    ipv6_timeout: [ 10, 0, "RED" ],
    "ipv6:nodns": [ 10, 0, "RED" ],
    broken_ipv6: [ 0, 0, "RED" ],
    "webfilter:blocked": [ -1, -1, "ORANGE" ],
    "webfilter:dsboth": [ 10, 10, "ORANGE" ],
    "webfilter:addons": [ 10, 10, "ORANGE" ],
    "webfilter:firefox": [ 10, 10, "ORANGE" ],
    NAT64: [ 7, 10, "ORANGE" ],
    "v6ns:ok": [ 10, 10, "GREEN" ],
    "v6ns:bad": [ 10, 9, "BLUE" ],
    "ip_timeout:firefox": [ 10, 10, "RED" ],
    "confused:obbo": [ 10, 9, "BLUE" ],
    "apple:dnsbug_aaaa": [ 10, 7, "BLUE" ],
    "apple:dnsbug_ds": [ 10, 7, "BLUE" ],
    "ipv4:no_address": [ 10, 10, "BLUE" ],
    "ipv6:no_address": [ 10, 10, "RED" ],
    no_address: [ 10, 10, "RED" ],
    opera: [ 10, 10, "ORANGE" ],
    "opera:turbo": [ 0, 0, "RED" ],
    "dualstack:safe": [ 10, 10, "GREEN" ],
    "dualstack:unsafe": [ 10, 10, "RED" ],
    "dualstack:mtu": [ 10, 10, "RED" ],
    buggydns1: [ 9, 0, "RED" ],
    tunnel_dumb: [ 10, 10, "ORANGE" ],
    he_tunnel_dumb: [ 10, 10, "BLUE" ],
    tunnel_6rd_dumb: [ 10, 10, "BLUE" ],
    proxy_via: [ 10, 10, "ORANGE" ],
    proxy_via_dumb: [ 10, 10, "ORANGE" ],
    broken: [ 0, 0, "BLUE" ],
    avoids_ipv6: [ 10, 10, "ORANGE" ]
};

GIGO.form_setup_value = function(r) {
    var s;
    s = r.status + "," + r.time_ms / 1e3;
    if (r.ipinfo) {
        if (r.ipinfo.via) {
            s = s + " " + r.ipinfo.via;
        }
    }
    return s;
};

GIGO.form_setup = function(tokens) {
    tokens = tokens.join(",");
    jQuery("[name=a]").val(GIGO.form_setup_value(GIGO.results.tests.test_a));
    jQuery("[name=aaaa]").val(GIGO.form_setup_value(GIGO.results.tests.test_aaaa));
    jQuery("[name=ds4]").val(GIGO.form_setup_value(GIGO.results.tests.test_ds4));
    jQuery("[name=ds6]").val(GIGO.form_setup_value(GIGO.results.tests.test_ds6));
    jQuery("[name=ipv4]").val(GIGO.form_setup_value(GIGO.results.tests.test_ipv4));
    jQuery("[name=ipv6]").val(GIGO.form_setup_value(GIGO.results.tests.test_ipv6));
    jQuery("[name=v6mtu]").val(GIGO.form_setup_value(GIGO.results.tests.test_v6mtu));
    jQuery("[name=v6ns]").val(GIGO.form_setup_value(GIGO.results.tests.test_v6ns));
    jQuery("[name=dsmtu]").val(GIGO.form_setup_value(GIGO.results.tests.test_dsmtu));
    jQuery("[name=ip4]").val(GIGO.results.ipv4.ip);
    jQuery("[name=ip6]").val(GIGO.results.ipv6.ip);
    jQuery("[name=ip6subtype]").val(GIGO.results.ipv6.subtype);
    jQuery("[name=tokens]").val(tokens);
    jQuery("[name=subdomain]").val(GIGO.mirrorconfig("site", "name"));
    jQuery(".progress_bar").remove();
    jQuery("[name=form_tab_main]").val(jQuery("#tab_main_inside")[0].outerHTML);
    jQuery("[name=form_config]").val(JSON.encode(MirrorConfig));
    jQuery("[name=form_results]").val(JSON.encode(GIGO.results));
};

GIGO.showform = function() {
    var msgs, share_text, share_link;
    jQuery("a.tabbutton_mail").attr("id", "contactme");
    GIGO.contact_wanted = 1;
    jQuery("#comments_wanted").show();
    jQuery("#comments_unwanted").hide();
    jQuery("#contact_form").show();
    jQuery("[name=purpose]").val("bug");
    share_text = "share your results";
    share_link = "<a href='#' onclick='return GIGO.tabnav(\"mail\");'>%1</a>";
    share_link = share_link.replace(/%1/, share_text);
    msgs = "I am most interested in discussing your setup with you, because it was been determined that <B>your IPv6 connectivity is broken</b>, or at least not fully understood. This is not normal; would you be willing to %share?";
    msgs = msgs.replace(/%share/, share_link);
    msgs = "<div><p><span id='highlighter'>" + msgs + "</span></p></div>";
    jQuery("#results_eof").before(msgs);
};

GIGO.showconfused = function(s) {
    var msgs, share_text, share_link, retest_text, retest_link;
    jQuery("a.tabbutton_mail").attr("id", "contactme");
    GIGO.contact_wanted = 1;
    jQuery("#comments_wanted").show();
    jQuery("#comments_unwanted").hide();
    share_text = "share your results";
    share_link = "<a href='#' onclick='return GIGO.tabnav(\"mail\");'>%1</a>";
    share_link = share_link.replace(/%1/, share_text);
    retest_text = "retest";
    retest_link = "<a href='#' onclick='return GIGO.retest();'>%1</a>";
    retest_link = retest_link.replace(/%1/, retest_text);
    msgs = "I am most interested in discussing your setup with you, because it was been determined that <B>your IPv6 connectivity is broken</b>, or at least not fully understood. This is not normal; would you be willing to %share?";
    msgs = msgs.replace(/%share/, share_link);
    msgs = msgs.replace(/%retest/, retest_link);
    msgs = "<div><p><span id='highlighter'>" + msgs + "</span></p></div>";
    msgs = msgs + "<div><p>" + "Result code" + " " + s + "</p></div>";
    jQuery("#results_eof").before(msgs);
    return false;
};

GIGO.debuggercomments = function(thisform) {
    var s = "[Debug info follows]\n" + GIGO._dumpObj(GIGO.results, ".", " ", 0);
    GIGO.showform();
    GIGO.tabnav("mail");
    jQuery("[name=notes]").val(s);
    return false;
};

GIGO.validate_form = function(thisform) {
    if (thisform.contact.value === null || thisform.contact.value === "") {
        if (!GIGO.validate_form.asked) {
            GIGO.validate_form.asked = 1;
            alert("Note: I can't contact you, if the contact info is blank. If you really want to submit this anonymously, hit Send Results again.");
            thisform.contact.focus();
            return false;
        }
    }
    return true;
};

GIGO.validate_form.asked = 0;

GIGO.sym_primary = {
    bbbb: "webfilter:blocked",
    bbbo: "webfilter:blocked",
    bbbs: "webfilter:blocked",
    bbbt: "webfilter:blocked",
    bbob: "webfilter:blocked",
    bboo: "webfilter:blocked",
    bbos: "webfilter:blocked",
    bbot: "webfilter:blocked",
    bbsb: "webfilter:blocked",
    bbso: "webfilter:blocked",
    bbss: "webfilter:blocked",
    bbst: "webfilter:blocked",
    bbtb: "webfilter:blocked",
    bbto: "webfilter:blocked",
    bbts: "webfilter:blocked",
    bbtt: "webfilter:blocked",
    bobb: "confused:ASK",
    bobo: "ipv6_only",
    bobs: "ipv6_only",
    bobt: "confused:ASK",
    boob: "confused:ASK",
    booo: "ipv6_only,webfilter:addons",
    boos: "webfilter:dsboth",
    boot: "confused:ASK",
    bosb: "confused:ASK",
    boso: "webfilter:dsboth",
    boss: "ipv6_only,webfilter:addons",
    bost: "confused:ASK",
    botb: "confused:ASK",
    boto: "confused:ASK",
    bots: "confused:ASK",
    bott: "confused:ASK",
    bsbb: "confused:ASK",
    bsbo: "ipv6_only",
    bsbs: "ipv6_only",
    bsbt: "confused:ASK",
    bsob: "confused:ASK",
    bsoo: "ipv6_only,ipv6_slow,webfilter:addons",
    bsos: "webfilter:dsboth",
    bsot: "confused:ASK",
    bssb: "confused:ASK",
    bsso: "webfilter:dsboth",
    bsss: "ipv6_only,ipv6_slow,webfilter:addons",
    bsst: "confused:ASK",
    bstb: "confused:ASK",
    bsto: "confused:ASK",
    bsts: "confused:ASK",
    bstt: "confused:ASK",
    btbb: "webfilter:blocked",
    btbo: "webfilter:blocked",
    btbs: "webfilter:blocked",
    btbt: "webfilter:blocked",
    btob: "webfilter:blocked",
    btoo: "webfilter:blocked",
    btos: "webfilter:blocked",
    btot: "webfilter:blocked",
    btsb: "webfilter:blocked",
    btso: "webfilter:blocked",
    btss: "webfilter:blocked",
    btst: "webfilter:blocked",
    bttb: "webfilter:blocked",
    btto: "webfilter:blocked",
    btts: "webfilter:blocked",
    bttt: "webfilter:blocked",
    obbb: "broken",
    obbo: "confused:obbo",
    obbs: "confused:obbs",
    obbt: "confused:ASK",
    obob: "ipv4_only",
    oboo: "ipv4_only,webfilter:addons",
    obos: "webfilter:dsboth",
    obot: "confused:ASK",
    obsb: "ipv4_only:ds_slow",
    obso: "webfilter:dsboth",
    obss: "ipv4_only,webfilter:addons",
    obst: "confused:ASK",
    obtb: "ipv4_only:ds_timeout",
    obto: "confused:ASK",
    obts: "confused:ASK",
    obtt: "broken",
    oobb: "confused:ASK",
    oobo: "dualstack:ipv6_preferred",
    oobs: "confused:ASK",
    oobt: "confused:ASK",
    ooob: "dualstack:ipv4_preferred",
    oooo: "dualstack:safe,webfilter:addons",
    ooos: "webfilter:dsboth",
    ooot: "dualstack:ipv4_preferred",
    oosb: "dualstack:slow",
    ooso: "webfilter:dsboth",
    ooss: "dualstack:safe,webfilter:addons",
    oost: "confused:ASK",
    ootb: "confused:ASK",
    ooto: "dualstack:ipv6_preferred",
    oots: "confused:ASK",
    oott: "confused:ASK",
    osbb: "confused:ASK",
    osbo: "confused:ASK",
    osbs: "confused:ASK",
    osbt: "confused:ASK",
    osob: "dualstack:ipv4_preferred,ipv6_slow",
    osoo: "dualstack:ipv4_prefered,webfilter:addons",
    osos: "webfilter:dsboth",
    osot: "confused:ASK",
    ossb: "dualstack:ipv4_preferred,ipv6_slow",
    osso: "webfilter:dsboth",
    osss: "dualstack:ipv4_prefered,webfilter:addons",
    osst: "confused:ASK",
    ostb: "confused:ASK",
    osto: "confused:ASK",
    osts: "confused:ASK",
    ostt: "confused:ASK",
    otbb: "broken",
    otbo: "confused:ASK",
    otbs: "confused:ASK",
    otbt: "broken",
    otob: "ipv4_only:ds_good,ipv6_timeout",
    otoo: "ipv4_only,webfilter:addons",
    otos: "webfilter:dsboth",
    otot: "confused:ASK",
    otsb: "ipv4_only:ds_slow,ipv6_timeout",
    otso: "webfilter:dsboth",
    otss: "ipv4_only,webfilter:addons",
    otst: "confused:ASK",
    ottb: "broken",
    otto: "confused:ASK",
    otts: "confused:ASK",
    ottt: "broken",
    sbbb: "confused:ASK",
    sbbo: "confused:ASK",
    sbbs: "confused:ASK",
    sbbt: "confused:ASK",
    sbob: "ipv4_only,ipv4_slow",
    sboo: "ipv4_only,webfilter:addons",
    sbos: "webfilter:dsboth",
    sbot: "confused:ASK",
    sbsb: "ipv4_only,ipv4_slow",
    sbso: "webfilter:dsboth",
    sbss: "ipv4_only,webfilter:addons",
    sbst: "confused:ASK",
    sbtb: "confused:ASK",
    sbto: "confused:ASK",
    sbts: "confused:ASK",
    sbtt: "confused:ASK",
    sobb: "dualstack:ipv4_preferred,ipv4_slow",
    sobo: "confused:ASK",
    sobs: "confused:ASK",
    sobt: "confused:ASK",
    soob: "dualstack:ipv4_preferred,ipv4_slow",
    sooo: "dualstack_ipv6_preferred,ipv4_slow,webfilter:addons",
    soos: "webfilter:dsboth",
    soot: "confused:ASK",
    sosb: "dualstack:ipv4_preferred,ipv4_slow",
    soso: "webfilter:dsboth",
    soss: "dualstack_ipv6_preferred,ipv4_slow,webfilter:addons",
    sost: "confused:ASK",
    sotb: "confused:ASK",
    soto: "confused:ASK",
    sots: "confused:ASK",
    sott: "confused:ASK",
    ssbb: "confused:ASK",
    ssbo: "confused:ASK",
    ssbs: "confused:ASK",
    ssbt: "confused:ASK",
    ssob: "confused:ASK",
    ssoo: "dualstack,ipv4_slow,ipv6_slow,webfilter:addons",
    ssos: "webfilter:dsboth",
    ssot: "confused:ASK",
    sssb: "dualstack:ipv4_preferred,ipv4_slow,ipv6_slow",
    ssso: "webfilter:dsboth",
    ssss: "dualstack,ipv4_slow,ipv6_slow,webfilter:addons",
    ssst: "confused:ASK",
    sstb: "confused:ASK",
    ssto: "confused:ASK",
    ssts: "confused:ASK",
    sstt: "confused:ASK",
    stbb: "confused:ASK",
    stbo: "confused:ASK",
    stbs: "confused:ASK",
    stbt: "confused:ASK",
    stob: "ipv4_only:ds_good,ipv6_timeout",
    stoo: "ipv4_only:ds_good,webfilter:addons",
    stos: "webfilter:dsboth",
    stot: "confused:ASK",
    stsb: "ipv4_only:ds_slow,ipv6_timeout",
    stso: "webfilter:dsboth",
    stss: "ipv4_only:ds_good,webfilter:addons",
    stst: "confused:ASK",
    sttb: "confused:ASK",
    stto: "confused:ASK",
    stts: "confused:ASK",
    sttt: "confused:ASK",
    tbbb: "webfilter:blocked",
    tbbo: "webfilter:blocked",
    tbbs: "webfilter:blocked",
    tbbt: "webfilter:blocked",
    tbob: "webfilter:blocked",
    tboo: "webfilter:blocked",
    tbos: "webfilter:blocked",
    tbot: "webfilter:blocked",
    tbsb: "webfilter:blocked",
    tbso: "webfilter:blocked",
    tbss: "webfilter:blocked",
    tbst: "webfilter:blocked",
    tbtb: "webfilter:blocked",
    tbto: "webfilter:blocked",
    tbts: "webfilter:blocked",
    tbtt: "webfilter:blocked",
    tobb: "confused:ASK",
    tobo: "ipv6_only",
    tobs: "confused:ASK",
    tobt: "confused:ASK",
    toob: "confused:ASK",
    tooo: "ipv6_only,webfilter:both",
    toos: "webfilter:dsboth",
    toot: "confused:ASK",
    tosb: "confused:ASK",
    toso: "webfilter:dsboth",
    toss: "ipv6_only,webfilter:both",
    tost: "confused:ASK",
    totb: "confused:ASK",
    toto: "confused:ASK",
    tots: "confused:ASK",
    tott: "confused:ASK",
    tsbb: "confused:ASK",
    tsbo: "confused:ASK",
    tsbs: "confused:ASK",
    tsbt: "confused:ASK",
    tsob: "confused:ASK",
    tsoo: "ipv6_only,webfilter:addons",
    tsos: "webfilter:dsboth",
    tsot: "confused:ASK",
    tssb: "confused:ASK",
    tsso: "webfilter:dsboth",
    tsss: "ipv6_only,webfilter:addons",
    tsst: "confused:ASK",
    tstb: "confused:ASK",
    tsto: "confused:ASK",
    tsts: "confused:ASK",
    tstt: "confused:ASK",
    ttbb: "webfilter:blocked",
    ttbo: "webfilter:blocked",
    ttbs: "webfilter:blocked",
    ttbt: "webfilter:blocked",
    ttob: "webfilter:blocked",
    ttoo: "webfilter:blocked",
    ttos: "webfilter:blocked",
    ttot: "webfilter:blocked",
    ttsb: "webfilter:blocked",
    ttso: "webfilter:blocked",
    ttss: "webfilter:blocked",
    ttst: "webfilter:blocked",
    tttb: "webfilter:blocked",
    ttto: "webfilter:blocked",
    ttts: "webfilter:blocked",
    tttt: "webfilter:blocked"
};

GIGO.sym_helpdesk = {
    "gg:gg": "Dual Stack",
    "gg:gt": "IPv4 plus Teredo",
    "gg:g6": "6to4",
    "gg:ga": "Dual Stack, Possible Tunnel",
    "gg:bg": "Dual Stack - but no Quad-A's (AAAA's)",
    "gg:bb": "IPv4 Only",
    "gg:bt": "IPv4 Only (Teredo Detected)",
    "gg:b6": null,
    "gg:ba": null,
    "gb:gg": "NAT64",
    "gt:gg": "NAT64",
    "gg:tb": "IPv4, plus Broken IPv6",
    "gb:gt": null,
    "gb:g6": null,
    "gb:ga": "NAT64, Possible Tunnel",
    "gt:ga": "NAT64, Possible Tunnel",
    "gb:bg": null,
    "gb:bb": null,
    "gb:bt": null,
    "gb:b6": null,
    "gb:ba": null,
    "gb:tb": null,
    "bb:gg": "IPv6 Only",
    "bb:gt": null,
    "bb:g6": null,
    "bb:ga": null,
    "bb:bg": null,
    "bb:bb": null,
    "bb:bt": null,
    "bb:b6": null,
    "bb:ba": null,
    "bb:tb": null
};

GIGO.sym_helpdesk_qcode = {
    "null": null,
    "Dual Stack": "46",
    "IPv4 plus Teredo": "4t",
    "6to4": "624",
    "Dual Stack, Possible Tunnel": "46t",
    "IPv4 Only": "4",
    "IPv4 Only (Teredo Detected)": "4",
    NAT64: "64",
    "IPv4, plus Broken IPv6": "112",
    "NAT64, Possible Tunnel": "64t",
    "IPv6 Only": 6
};

GIGO.oc = function(a) {
    var o, i;
    o = {};
    for (i = 0; i < a.length; i = i + 1) {
        o[a[i]] = "";
    }
    return o;
};

GIGO.isdef = function(x) {
    return typeof x !== "undefined";
};

GIGO.cgistats = function(name) {
    var s, status, time_ms, id;
    id = "test_" + name;
    status = GIGO.results.tests[id].status;
    time_ms = GIGO.results.tests[id].time_ms;
    s = "&" + name + "=" + status + "," + time_ms;
    return s;
};

GIGO.expand_abbreviation = function(c) {
    if (c === "o") {
        return "ok";
    }
    if (c === "b") {
        return "bad";
    }
    if (c === "t") {
        return "timeout";
    }
    if (c === "s") {
        return "slow";
    }
    return "[" + "unknown expansion" + " " + c + "]";
};

GIGO.check_precheck = function() {
    return;
};

GIGO.check_results = function() {
    var delta, mini_primary, mini_secondary, tokens, score_transition, score_strict, msgs, i, token, messages_plaintext, token_expanded, tokens_expanded;
    tokens_expanded = [];
    GIGO.check_precheck();
    if (GIGO.queue.length > 0) {
        return;
    }
    GIGO.show_debug();
    GIGO.repeated = GIGO.repeated + 1;
    delta = GIGO.getms() - GIGO.start_time;
    if (GIGO.repeated <= GIGO.retry_min || GIGO.repeated <= GIGO.retry_max && GIGO.delta < GIGO.retry_until) {
        if (GIGO.repeat_only_if_slow === 0 || GIGO.ministates([ "a", "aaaa", "ds4", "ds6", "ipv4", "ipv6", "v6mtu", "v6ns" ]).match(/s/)) {
            GIGO.restart_tests();
            return;
        }
    }
    GIGO.finished = 1;
    GIGO.update_progress(GIGO);
    GIGO.fix_comment_form_and_tab();
    tokens = GIGO.identify_symptoms();
    mini_primary = GIGO.ministates([ "a", "aaaa", "ds4", "ds6" ]);
    mini_secondary = GIGO.ministates([ "ipv4", "ipv6", "v6mtu", "v6ns" ]);
    score_transition = 100;
    score_strict = 100;
    msgs = "";
    messages_plaintext = [];
    for (i = 0; i < tokens.length; i = i + 1) {
        token = tokens[i];
        if (GIGO.isdef(GIGO.scores[token])) {
            token_expanded = {};
            token_expanded.token = token;
            token_expanded.score_ipv4 = GIGO.scores[token][0];
            token_expanded.score_ipv6 = GIGO.scores[token][1];
            token_expanded.color = GIGO.scores[token][2];
            token_expanded.text = GIGO.messages[token];
            tokens_expanded.push(token_expanded);
            if (token_expanded.score_ipv4 <= score_transition) {
                score_transition = token_expanded.score_ipv4;
            }
            if (token_expanded.score_ipv6 <= score_strict) {
                score_strict = token_expanded.score_ipv6;
            }
            msgs = msgs + "<div><p>" + token_expanded.text + "</p></div>";
            messages_plaintext.push(token_expanded.text);
        } else {
            token_expanded = {};
            token_expanded.token = token;
            token_expanded.color = "YELLOW";
            token_expanded.score_ipv4 = 10;
            token_expanded.score_ipv6 = 10;
            token_expanded.text = "(" + "unknown result code" + ": " + token + ")";
            tokens_expanded.push(token_expanded);
            msgs = msgs + "<div><p>" + token_expanded.text + "</p></div>";
            messages_plaintext.push(token_expanded.text);
        }
    }
    if (GIGO.oc(tokens).hasOwnProperty("confused:ASK")) {
        tokens.push("confused:" + mini_primary + ":" + mini_secondary);
    }
    if (score_transition === 100) {
        score_transition = "?";
    }
    if (score_strict === 100) {
        score_strict = "?";
    }
    if (score_strict > 7) {
        GIGO.start_sites();
    }
    GIGO.results.tokens = tokens;
    GIGO.results.score_transition = score_transition;
    GIGO.results.score_strict = score_strict;
    GIGO.results.divs = msgs;
    GIGO.results.messages_plaintext = messages_plaintext;
    GIGO.results.debug_code = mini_primary + ":" + mini_secondary;
    GIGO.results.tokens_expanded = tokens_expanded;
    GIGO.show_debug();
    GIGO.finish_helpdesk();
    GIGO.fix_footer();
    GIGO.facebook_like();
    GIGO.twitter_tweet();
    GIGO.send_survey(tokens);
    GIGO.show_results();
    GIGO.form_setup(tokens);
    GIGO.show_debug();
};

GIGO.facebook_like = function() {
    if (GIGO.mirrorconfig("facebook", "enable", 0)) {
        jQuery("#facebook_like").replaceWith('<div id="fb-root"></div><fb:like href="http://' + GIGO.mirrorconfig("site", "name", null) + '" send="false" width="450" show_faces="false" font=""></fb:like>');
        var s = document.createElement("SCRIPT"), s1 = document.getElementsByTagName("SCRIPT")[0];
        s.type = "text/javascript";
        s.async = true;
        s.src = "http://connect.facebook.net/en_US/all.js#xfbml=1";
        s1.parentNode.insertBefore(s, s1);
    }
};

GIGO.twitter_tweet = function() {
    if (GIGO.mirrorconfig("twitter", "enable", 0)) {
        jQuery("#twitter_tweet").replaceWith('<a href="http://twitter.com/share" class="twitter-share-button" data-count="horizontal" data-via="' + GIGO.mirrorconfig("twitter", "name") + '">Tweet</a>');
        var s = document.createElement("SCRIPT"), s1 = document.getElementsByTagName("SCRIPT")[0];
        s.type = "text/javascript";
        s.async = true;
        s.src = "http://platform.twitter.com/widgets.js";
        s1.parentNode.insertBefore(s, s1);
    }
};

GIGO.asn_same = {
    comcast: [ 7922, 7853, 7757, 7725, 7016, 7015, 6161, 53297, 393232, 36733, 36732, 36377, 36196, 33668, 33667, 33666, 33665, 33664, 33663, 33662, 33661, 33660, 33659, 33658, 33657, 33656, 33655, 33654, 33653, 33652, 33651, 33650, 33542, 33491, 33490, 33489, 33287, 23266, 23253, 22909, 22258, 21508, 20214, 16748, 14668, 13385, 13367, 11025 ],
    surewest: [ 14051 ],
    aarnet: [ 757, 56132 ],
    "tmobile-usa": [ 21928, 22140 ],
    att: [ 7132, 7018, 6389 ]
};

GIGO.asn_native = {
    668: 1
};

GIGO.ministates = function(which) {
    var s, i, key, v, tests;
    tests = GIGO.results.tests;
    s = "";
    for (i = 0; i < which.length; i = i + 1) {
        key = which[i];
        try {
            v = GIGO.results.tests["test_" + key].status.charAt(0);
        } catch (e) {
            v = "?";
        }
        s = s + v;
    }
    return s;
};

GIGO.find_evidence_of_noscript = function(tests, res) {
    var i, key_json, key_img, test_json, test_img, key, keys, blocked;
    keys = [ "a", "aaaa", "ds", "ipv4", "ipv6", "v6mtu", "v6ns", "dsmtu" ];
    for (i = 0; i < keys.length; i = i + 1) {
        key = keys[i];
        key_json = "test_" + key;
        key_img = "test_" + key + "_img";
        if (tests.hasOwnProperty(key_img)) {
            test_json = tests[key_json].status;
            test_img = tests[key_img].status;
            if (test_img.match(/^[os]/)) {
                if (test_json.match(/^[bt]/)) {
                    blocked = tests[key_json].url;
                    res.push("webfilter:addons");
                    if (Browser.firefox) {
                        res.push("webfilter:firefox");
                    }
                    if (Browser.opera) {
                        res.push("opera");
                    }
                    res.push("webfilter:test_" + key);
                    blocked = blocked.replace(/fill=xxxx*/, "fill=xxx...xxx");
                    GIGO.messages["webfilter:test_" + key] = "Your browser blocked" + " " + blocked;
                    GIGO.scores["webfilter:test_" + key] = [ 10, 10, "ORANGE" ];
                }
            }
        }
    }
};

GIGO.fallback_to_image_tests = function(tests, res) {
    var keys, i, key, key_json, key_img, test_json, test_img;
    keys = [ "a", "aaaa", "ds", "ipv4", "ipv6", "v6mtu", "v6ns", "dsmtu" ];
    for (i = 0; i < keys.length; i = i + 1) {
        key = keys[i];
        key_json = "test_" + key;
        key_img = "test_" + key + "_img";
        if (tests.hasOwnProperty(key_img)) {
            test_json = tests[key_json].status;
            test_img = tests[key_img].status;
            if (test_img.match(/^[os]/)) {
                if (test_json.match(/^[bt]/)) {
                    tests["failed_" + key] = tests[key_json];
                    tests[key_json] = tests[key_img];
                    GIGO.update_status("test_" + key);
                    GIGO.update_url("test_" + key);
                    GIGO.show_debug();
                    if (key === "ds") {
                        tests.failed_test_ds4 = tests.test_ds4;
                        tests.failed_test_ds6 = tests.test_ds6;
                        tests.test_ds4 = tests.test_ds_img;
                        tests.test_ds6 = tests.test_ds_img;
                        GIGO.update_status("test_ds4");
                        GIGO.update_status("test_ds6");
                        GIGO.update_url("test_ds4");
                        GIGO.update_url("test_ds6");
                        GIGO.show_debug();
                    }
                }
            }
        }
    }
};

GIGO.dedupe_res = function(res) {
    var ret, unique, i;
    ret = [];
    unique = {};
    if (res.length) {
        for (i = 0; i < res.length; i = i + 1) {
            if (!unique.hasOwnProperty(res[i])) {
                ret.push(res[i]);
                unique[res[i]] = 1;
            }
        }
    }
    return ret;
};

GIGO.ipinfo_in_tests = function(tests, name) {
    var keys, key, i;
    keys = [ "a", "aaaa", "ds", "ipv4", "ipv6", "v6mtu", "v6ns", "dsmtu" ];
    for (i = 0; i < keys.length; i = i + 1) {
        key = "test_" + keys[i];
        if (tests.hasOwnProperty(key)) {
            if (tests[key].hasOwnProperty("ipinfo")) {
                if (tests[key].ipinfo.hasOwnProperty(name)) {
                    return tests[key].ipinfo[name];
                }
            }
        }
    }
    return null;
};

GIGO.check6RD = function(addr4, addr6) {
    var i, bytes, addr4Bits, addr6Bits, chunk, index;
    bytes = addr4.split(".");
    addr4Bits = "";
    for (i = 0; i < 4; i = i + 1) {
        chunk = parseInt(bytes[i], 10).toString(2);
        while (chunk.length < 8) chunk = "0" + chunk;
        addr4Bits = addr4Bits + chunk;
    }
    bytes = addr6.split(":");
    addr6Bits = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
    for (i = 2; i < 4; i = i + 1) {
        chunk = parseInt(bytes[i], 16).toString(2);
        while (chunk.length < 16) chunk = "0" + chunk;
        addr6Bits = addr6Bits + chunk;
    }
    while (addr4Bits.length >= 16) {
        index = addr6Bits.indexOf(addr4Bits);
        if (index >= 0) return addr4Bits.length + " bits of the IPv4 address are embedded in the IPv6 address starting at " + index;
        addr4Bits = addr4Bits.substr(1, addr4Bits.length - 1);
    }
    return 0;
};

GIGO.identify_symptoms = function() {
    var a, aaaa, ds4, ds6, ipv4, ipv6, v6mtu, v6ns, tunnel, tunnel_6rd, teredo, sixfour, mini_primary, mini_secondary, res, failed_pmtud, x, x_array, i, tests, via, dsmtu, a, b, ia, ib, a4, a6, k, i, r, f4, f6;
    res = [];
    tests = GIGO.results.tests;
    GIGO.find_evidence_of_noscript(tests, res);
    GIGO.fallback_to_image_tests(tests, res);
    a = tests.test_a.status;
    aaaa = tests.test_aaaa.status;
    ds4 = tests.test_ds4.status;
    ds6 = tests.test_ds6.status;
    ipv4 = tests.test_ipv4.status;
    ipv6 = tests.test_ipv6.status;
    v6mtu = tests.test_v6mtu.status;
    v6ns = tests.test_v6ns.status;
    dsmtu = tests.test_dsmtu.status;
    via = GIGO.ipinfo_in_tests(tests, "via");
    tunnel = GIGO.results.ipv4.asn !== GIGO.results.ipv6.asn && GIGO.results.ipv4.asn && GIGO.results.ipv6.asn;
    teredo = GIGO.results.ipv6.subtype === "Teredo";
    sixfour = GIGO.results.ipv6.subtype === "6to4";
    if (GIGO.results.ipv4.ip && GIGO.results.ipv6.ip) tunnel_6rd = GIGO.check6RD(GIGO.results.ipv4.ip, GIGO.results.ipv6.ip); else tunnel_6rd = 0;
    if (GIGO.results.ipv4.asnlist && GIGO.results.ipv6.asnlist) {
        a = GIGO.results.ipv4.asnlist.split(";");
        b = GIGO.results.ipv6.asnlist.split(";");
        for (ia = 0; ia < a.length; ia = ia + 1) {
            for (ib = 0; ib < b.length; ib = ib + 1) {
                if (a[ia] === b[ib]) {
                    tunnel = 0;
                }
            }
        }
    }
    if (GIGO.results.ipv4.asn && GIGO.results.ipv6.asn) {
        a4 = parseInt(GIGO.results.ipv4.asn, 10);
        a6 = parseInt(GIGO.results.ipv6.asn, 10);
        for (k in GIGO.asn_same) {
            if (GIGO.asn_same.hasOwnProperty(k)) {
                r = GIGO.asn_same[k];
                for (i = 0; i < r.length; i = i + 1) {
                    if (r[i] === a4) f4 = 1;
                    if (r[i] === a6) f6 = 1;
                }
                if (f4 && f6) tunnel = 0;
            }
        }
    }
    if (GIGO.results.ipv6.ip) {
        a6 = parseInt(GIGO.results.ipv6.asn, 10);
        if (GIGO.asn_native[a6]) {
            tunnel = 0;
        }
    }
    GIGO.helpdesk.tunnel = tunnel;
    GIGO.helpdesk.teredo = teredo;
    GIGO.helpdesk.sixfour = sixfour;
    mini_primary = GIGO.ministates([ "a", "aaaa", "ds4", "ds6" ]);
    mini_secondary = GIGO.ministates([ "ipv4", "ipv6", "v6mtu", "v6ns" ]);
    GIGO.helpdesk.mini_primary = mini_primary;
    GIGO.helpdesk.mini_secondary = mini_secondary;
    x = GIGO.sym_primary[mini_primary];
    x_array = x.split(",");
    for (i = 0; i < x_array.length; i = i + 1) {
        res.push(x_array[i]);
    }
    if (dsmtu === "ok") {
        res.unshift("dualstack:safe");
    } else {
        res.unshift("dualstack:unsafe");
    }
    if (!teredo && !sixfour) {
        if (tunnel) {
            res.unshift("tunnel_dumb");
        } else if (tunnel_6rd) {
            res.unshift("tunnel_6rd_dumb");
        }
    }
    if (via) {
        res.unshift("proxy_via_dumb");
    }
    if (!GIGO.results.ipv4.ip && !GIGO.results.ipv6.ip) {
        res.unshift("no_address");
    } else if (!GIGO.results.ipv4.ip) {
        res.unshift("ipv4:no_address");
    } else if (!GIGO.results.ipv6.ip) {
        res.unshift("ipv6:no_address");
    }
    if (!teredo && !sixfour) {
        if (GIGO.results.ipv4.ip && GIGO.results.ipv6.ip) {
            if (mini_primary.match(/^[os][os][os][bt]/)) {
                res.unshift("avoids_ipv6");
            }
        }
    }
    if (mini_secondary.match(/^[bst][bst]/)) {
        res.push("No Direct IP");
    } else if (mini_secondary.match(/^[bt]./) && mini_primary.match(/^[os]./)) {
        0;
    } else if (mini_secondary.match(/^.[bt]/) && mini_primary.match(/^.[os]/)) {
        res.push("No Direct IPv6");
    }
    if (mini_primary.match(/o/) && mini_secondary.match(/^ttt/)) {
        if (Browser.Engine.gecko) {
            res.push("ip_timeout:firefox");
        }
    }
    if (mini_primary.match(/^[os][os]/) && mini_secondary.match(/^[bt][os]/)) {
        res.push("NAT64");
    }
    if (teredo) {
        if (aaaa === "bad") {
            res.push("teredo-minimum");
        } else if (mini_primary.match(/^..[os]b/)) {
            res.unshift("teredo-v4pref");
        } else {
            res.push("teredo");
        }
    }
    if (sixfour) {
        res.push("6to4");
    }
    if (!teredo && aaaa === "bad" && ipv6 === "ok") {
        res.push("ipv6:nodns");
    }
    if (ds4 === "ok" || ds4 === "slow" || ds6 === "ok" || ds6 === "slow") {
        if (v6ns === "ok" || v6ns === "slow") {
            res.push("v6ns:ok");
        } else {
            res.push("v6ns:bad");
        }
    }
    if (tests.hasOwnProperty("test_buggydns1")) {
        if (tests.test_buggydns1.status === "affected") {
            res.push("buggydns1");
        }
    }
    if (Browser.opera) {
        if (aaaa === "ok" && (v6mtu === "timeout" || v6mtu === "slow")) {
            res.push("IPv6 MTU");
            failed_pmtud = 1;
        }
    } else {
        if (aaaa === "ok" && (v6mtu === "bad" || v6mtu === "timeout" || v6mtu === "slow" || dsmtu === "bad" || dsmtu === "timeout" || dsmtu === "slow")) {
            res.push("IPv6 MTU");
            failed_pmtud = 1;
        }
    }
    GIGO.helpdesk.failed_pmtud = failed_pmtud;
    for (i = 0; i < res.length; i += 1) {
        if (failed_pmtud) {
            if (res[i] === "dualstack:safe") {
                res[i] = "dualstack:mtu";
            }
            if (res[i] === "dualstack:unsafe") {
                res[i] = "dualstack:mtu";
            }
        }
        if (Browser.Platform.mac || Browser.Platform.ios) {
            if (res[i] === "confused:obbo") {
                res[i] = "apple:dnsbug_aaaa";
            }
            if (res[i] === "confused:ASK") {
                if (mini_primary.match(/^obb[sob]/)) {
                    res[i] = "apple:dnsbug_aaaa";
                }
            }
        }
        if (res[i] === "confused:ASK") {
            if (mini_primary.match(/^ottt/) && mini_secondary.match(/^ottt/)) {
                res[i] = "broken_ipv6";
            }
        }
    }
    if (res.length === 0) {
        res.push("Unknown");
    }
    res = GIGO.dedupe_res(res);
    return res;
};

try {
    GIGO.tryme = 1;
} catch (e) {
    GIGO = {};
}

GIGO.hide_os_osx = function() {
    jQuery(".os_osx").hide(250);
};

GIGO.hide_os_ios = function() {
    jQuery(".os_ios").hide(250);
};

GIGO.hide_os_other = function() {
    jQuery(".os_other").hide(250);
};

GIGO.hide_os_windows = function() {
    jQuery(".os_windows").hide(250);
};

GIGO.hide_os_linux = function() {
    jQuery(".os_linux").hide(250);
};

GIGO.hide_os_all = function() {
    GIGO.hide_os_other();
    GIGO.hide_os_osx();
    GIGO.hide_os_ios();
    GIGO.hide_os_windows();
    GIGO.hide_os_linux();
};

GIGO.show_os_osx = function() {
    jQuery(".os_osx").show(250);
};

GIGO.show_os_ios = function() {
    jQuery(".os_ios").show(250);
};

GIGO.show_os_windows = function() {
    jQuery(".os_windows").show(250);
};

GIGO.show_os_linux = function() {
    jQuery(".os_linux").show(250);
};

GIGO.show_os_other = function() {
    jQuery(".os_other").show(250);
};

GIGO.show_os_all = function() {
    GIGO.show_os_other();
    GIGO.show_os_osx();
    GIGO.show_os_ios();
    GIGO.show_os_windows();
    GIGO.show_os_linux();
};

GIGO.show_os_only_osx = function() {
    GIGO.hide_os_all();
    GIGO.show_os_osx();
};

GIGO.show_os_only_ios = function() {
    GIGO.hide_os_all();
    GIGO.show_os_ios();
};

GIGO.show_os_only_windows = function() {
    GIGO.hide_os_all();
    GIGO.show_os_windows();
};

GIGO.show_os_only_linux = function() {
    GIGO.hide_os_all();
    GIGO.show_os_linux();
};

GIGO.show_os_start = function() {
    if (Browser.Platform.mac) {
        GIGO.show_os_only_osx();
    } else if (Browser.Platform.windows) {
        GIGO.show_os_only_windows();
    } else if (Browser.Platform.linux) {
        GIGO.show_os_only_linux();
    } else if (Browser.Platform.ios) {
        GIGO.show_os_only_ios();
    } else {}
};

GIGO.sites_parsed = {
    "8n1.org": {
        hide: "0",
        loc: "NL",
        monitor: "Sander Smeenk <sander@bit.nl>",
        provider: "8n1.org - a simple pastebin",
        site: "8n1.org",
        v4: "http://ip4.8n1.org/test.gif",
        v6: "http://ip6.8n1.org/test.gif"
    },
    "aa.net.uk": {
        hide: "0",
        loc: "UK",
        monitor: "Adrian Kennard <a@k.gg>",
        provider: "AAISP (UK IPv6 ISP)",
        site: "aa.net.uk",
        v4: "http://ip4.aa.net.uk/images/aaisp_logo.png",
        v6: "http://ip6.aa.net.uk/images/aaisp_logo.png"
    },
    "campaya.co.uk": {
        hide: "0",
        loc: "UK",
        monitor: "Claus Pedersen <clausp@campaya.com>",
        provider: "Campaya",
        site: "campaya.co.uk",
        v4: "http://ipv4.campaya.co.uk/apple-touch-icon.png",
        v6: "http://ipv6.campaya.co.uk/apple-touch-icon.png"
    },
    "chelloo.com": {
        hide: "0",
        loc: "NL",
        monitor: "Rene Kemp <rene.kemp@outlook.com>",
        provider: "Chelloo",
        site: "chelloo.com",
        v4: "http://ipv4.chelloo.com/images/pixel.gif",
        v6: "http://ipv6.chelloo.com/images/pixel.gif"
    },
    "duplimaster.com": {
        hide: "0",
        loc: "ES",
        monitor: "Jesus Vara <jvara@e-impresion.es>",
        provider: "duplimaster.com",
        site: "duplimaster.com",
        v4: "http://ipv4.duplimaster.com/public/images/logo-sombra.png",
        v6: "http://ipv6.duplimaster.com/public/images/logo-sombra.png"
    },
    "eurobilltracker.com": {
        hide: "0",
        loc: "FI",
        monitor: "Anssi Johansson <anssi@miuku.net>",
        provider: "EuroBillTracker",
        site: "eurobilltracker.com",
        v4: "http://ipv4.test-ipv6.eurobilltracker.com/img/1x1.gif",
        v6: "http://ipv6.test-ipv6.eurobilltracker.com/img/1x1.gif"
    },
    "google.com": {
        hide: "0",
        loc: "global",
        provider: "Google",
        site: "google.com",
        v4: "http://test-ipv6-dot-com-v6exp3-v4.metric.gstatic.com/v6exp3/6.gif",
        v6: "http://test-ipv6-dot-com-v6exp3-v6.metric.gstatic.com/v6exp3/6.gif"
    },
    "he.net": {
        hide: "0",
        loc: "US (CA)",
        monitor: "Mike Tindle <mtindle@he.net>",
        provider: "HE.net",
        site: "he.net",
        v4: "http://ipv4.tunnelbroker.net/images/helogo.gif",
        v6: "http://ipv6.tunnelbroker.net/images/helogo.gif"
    },
    "ipv6-test.pl": {
        hide: "0",
        loc: "PL",
        mirror: "1",
        provider: "Net-Admin",
        site: "ipv6-test.pl",
        v4: "http://ipv4.ipv6-test.pl/images-nc/knob_green.png",
        v6: "http://ipv6.ipv6-test.pl/images-nc/knob_green.png"
    },
    "nic.br": {
        hide: "0",
        loc: "BR",
        monitor: "Antonio M. Moreiras <moreiras@nic.br>",
        provider: "NIC.br",
        site: "nic.br",
        v4: "http://v4.ipv6.br/img/logo-ipv6.png",
        v6: "http://v6.ipv6.br/img/logo-ipv6.png"
    },
    "nsx.de": {
        hide: "0",
        loc: "DE",
        monitor: "Stephan Fiebrandt <stephan@nsx.de>",
        provider: "Stephan Fiebrandt (personal)",
        site: "nsx.de",
        v4: "http://ipv4.nsx.de/images/knob_valid_green.png",
        v6: "http://ipv6.nsx.de/images/knob_valid_green.png"
    },
    "sixte.st": {
        hide: "0",
        loc: "SG",
        mirror: "1",
        monitor: "Delan Azabani <delan@azabani.com>",
        provider: "Delan Azabani",
        site: "sixte.st",
        v4: "http://ipv4.sixte.st/images-nc/knob_green.png",
        v6: "http://ipv6.sixte.st/images-nc/knob_green.png"
    },
    "snozzages.com": {
        hide: "0",
        loc: "US (VA)",
        monitor: "Warren Kumari <warren@kumari.net>",
        provider: "Warren Kumari",
        site: "snozzages.com",
        v4: "http://ipv4.v6test.snozzages.com/1x1.gif",
        v6: "http://ipv6.v6test.snozzages.com/1x1.gif"
    },
    "stdio.be": {
        hide: "0",
        loc: "DE",
        provider: "Andrew Yourtchenko (personal)",
        site: "stdio.be",
        v4: "http://ipv4.stdio.be/images/knob_valid_green.png",
        v6: "http://ipv6.stdio.be/images/knob_valid_green.png"
    },
    "test-ipv6-ct.comcast.net": {
        hide: "0",
        loc: "US",
        mirror: "1",
        monitor: "Comcast IPv6 Team <comcast-ipv6@cable.comcast.com>",
        provider: "Comcast",
        site: "test-ipv6-ct.comcast.net",
        transparent: "1",
        v4: "http://ipv4.test-ipv6-ct.comcast.net/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6-ct.comcast.net/images-nc/knob_green.png"
    },
    "test-ipv6-pa.comcast.net": {
        hide: "0",
        loc: "US",
        mirror: "1",
        monitor: "Comcast IPv6 Team <comcast-ipv6@cable.comcast.com>",
        provider: "Comcast",
        site: "test-ipv6-pa.comcast.net",
        transparent: "1",
        v4: "http://ipv4.test-ipv6-pa.comcast.net/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6-pa.comcast.net/images-nc/knob_green.png"
    },
    "test-ipv6.alpinedc.ch": {
        hide: "0",
        loc: "CH",
        mirror: "1",
        monitor: "Sebastien Morier <smorier@alpinedc.ch>",
        provider: "AlpineDC",
        site: "test-ipv6.alpinedc.ch",
        v4: "http://ipv4.test-ipv6.alpinedc.ch/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.alpinedc.ch/images-nc/knob_green.png"
    },
    "test-ipv6.ams.vr.org": {
        hide: "0",
        loc: "NL",
        mirror: "1",
        monitor: "jfesler@gigo.com",
        provider: "vr.org",
        site: "test-ipv6.ams.vr.org",
        v4: "http://ipv4.test-ipv6.ams.vr.org/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.ams.vr.org/images-nc/knob_green.png"
    },
    "test-ipv6.arbor.net": {
        hide: "0",
        loc: "US",
        mirror: "1",
        monitor: "Bill Cerveny <admin@v6research.net>",
        provider: "Arbor Networks",
        site: "test-ipv6.arbor.net",
        v4: "http://ipv4.test-ipv6.arbor.net/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.arbor.net/images-nc/knob_green.png"
    },
    "test-ipv6.belwue.net": {
        hide: "0",
        loc: "DE",
        mirror: "1",
        monitor: "BelWue NOC <ip@belwue.de>",
        provider: "BelWü",
        site: "test-ipv6.belwue.net",
        v4: "http://ipv4.test-ipv6.belwue.net/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.belwue.net/images-nc/knob_green.png"
    },
    "test-ipv6.carnet.hr": {
        hide: "0",
        loc: "HR",
        mirror: "1",
        monitor: "CARNet <sysadm@carnet.hr>",
        provider: "Croatian Academic and Research Network",
        site: "test-ipv6.carnet.hr",
        v4: "http://ipv4.test-ipv6.carnet.hr/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.carnet.hr/images-nc/knob_green.png"
    },
    "test-ipv6.ceengine.eu": {
        hide: "0",
        loc: "RO",
        mirror: "1",
        monitor: "NOC @ CEENGINE <valeriu@roedu.net>",
        provider: "Central and Eastern European Networking Engine",
        site: "test-ipv6.ceengine.eu",
        v4: "http://ipv4.test-ipv6.ceengine.eu/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.ceengine.eu/images-nc/knob_green.png"
    },
    "test-ipv6.chi.vr.org": {
        hide: "0",
        loc: "US IL",
        mirror: "1",
        monitor: "jfesler@gigo.com",
        provider: "vr.org",
        site: "test-ipv6.chi.vr.org",
        v4: "http://ipv4.test-ipv6.chi.vr.org/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.chi.vr.org/images-nc/knob_green.png"
    },
    "test-ipv6.co.za": {
        hide: "0",
        loc: "ZA",
        mirror: "1",
        monitor: "Multisource Support <support@multisource.co.za>",
        provider: "Multisource Telecoms",
        site: "test-ipv6.co.za",
        v4: "http://ipv4.test-ipv6.co.za/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.co.za/images-nc/knob_green.png"
    },
    "test-ipv6.com": {
        hide: "0",
        loc: "US CA",
        mirror: "1",
        provider: "Jason Fesler",
        site: "test-ipv6.com",
        v4: "http://ipv4.test-ipv6.com/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.com/images-nc/knob_green.png"
    },
    "test-ipv6.com.au": {
        hide: "0",
        loc: "AU",
        mirror: "1",
        provider: "Futzle Industries",
        site: "test-ipv6.com.au",
        v4: "http://ipv4.test-ipv6.com.au/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.com.au/images-nc/knob_green.png"
    },
    "test-ipv6.cz": {
        hide: "0",
        loc: "CZ",
        mirror: "1",
        monitor: "NOC NIC <noc@nic.cz>",
        provider: "nic.cz",
        site: "test-ipv6.cz",
        v4: "http://ipv4.test-ipv6.cz/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.cz/images-nc/knob_green.png"
    },
    "test-ipv6.ernet.in": {
        loc: "IN",
        mirror: "1",
        monitor: "Praveen Misra <praveen@ipv6.ernet.in>",
        provider: "IPv6 Division of ERNET India",
        site: "test-ipv6.ernet.in",
        v4: "http://ipv4.test-ipv6.ernet.in/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.ernet.in/images-nc/knob_green.png"
    },
    "test-ipv6.fratec.net": {
        hide: "0",
        loc: "CR",
        mirror: "1",
        provider: "Sistemas Fratec S.A.",
        site: "test-ipv6.fratec.net",
        v4: "http://ipv4.test-ipv6.fratec.net/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.fratec.net/images-nc/knob_green.png"
    },
    "test-ipv6.go6.si": {
        hide: "0",
        loc: "SI",
        mirror: "1",
        monitor: "Jan Zorz <jan@go6.si>",
        provider: "Go6 Lab - Slovenian IPv6 Iniciative",
        site: "test-ipv6.go6.si",
        v4: "http://ipv4.test-ipv6.go6.si/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.go6.si/images-nc/knob_green.png"
    },
    "test-ipv6.hu": {
        hide: "0",
        loc: "HU",
        mirror: "1",
        monitor: "Polaris-N Systems <info@polaris-n.hu>",
        provider: "Polaris-N Systems",
        site: "test-ipv6.hu",
        v4: "http://ipv4.test-ipv6.hu/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.hu/images-nc/knob_green.png"
    },
    "test-ipv6.iad.vr.org": {
        hide: "0",
        loc: "US VA",
        mirror: "1",
        monitor: "jfesler@gigo.com",
        provider: "vr.org",
        site: "test-ipv6.iad.vr.org",
        v4: "http://ipv4.test-ipv6.iad.vr.org/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.iad.vr.org/images-nc/knob_green.png"
    },
    "test-ipv6.jp": {
        hide: "0",
        loc: "JP",
        mirror: "1",
        monitor: "Shin Shirahata <inquiry@test-ipv6.jp>",
        provider: "BIGLOBE, Inc/Fullroute Pte. Ltd",
        site: "test-ipv6.jp",
        v4: "http://ipv4.test-ipv6.jp/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.jp/images-nc/knob_green.png"
    },
    "test-ipv6.lazypaddle.com": {
        hide: "0",
        loc: "US WI",
        mirror: "1",
        monitor: "Dale Hartung <dale@dghartung.com>",
        provider: "Dale Hartung",
        site: "test-ipv6.lazypaddle.com",
        v4: "http://ipv4.test-ipv6.lazypaddle.com/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.lazypaddle.com/images-nc/knob_green.png"
    },
    "test-ipv6.monash.edu": {
        hide: "0",
        loc: "AU",
        mirror: "1",
        monitor: "John Mann <John.Mann@monash.edu>",
        provider: "Monash University",
        site: "test-ipv6.monash.edu",
        v4: "http://ipv4.test-ipv6.monash.edu/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.monash.edu/images-nc/knob_green.png"
    },
    "test-ipv6.netiter.dk": {
        hide: "0",
        loc: "DE",
        monitor: "Netiter Aps <kontakt@netiter.dk>",
        provider: "Netiter ApS",
        site: "test-ipv6.netiter.dk",
        v4: "http://test-ipv6.com.i42.test-ipv6.easyv6.net/ipv6-test.png",
        v6: "http://test-ipv6.com.i32.test-ipv6.easyv6.net/ipv6-test.png"
    },
    "test-ipv6.nl": {
        hide: "0",
        loc: "NL",
        mirror: "1",
        monitor: "Teun Vink <teun@bit.nl>",
        provider: "BIT BV",
        site: "test-ipv6.nl",
        v4: "http://ipv4.test-ipv6.nl/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.nl/images-nc/knob_green.png"
    },
    "test-ipv6.no": {
        hide: "0",
        loc: "NO",
        mirror: "1",
        monitor: "Brynjar Eide <test-ipv6@availo.no>",
        provider: "Availo AS",
        site: "test-ipv6.no",
        v4: "http://ipv4.test-ipv6.no/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.no/images-nc/knob_green.png"
    },
    "test-ipv6.polkam.go.id": {
        hide: "0",
        loc: "ID",
        mirror: "1",
        monitor: "vicky@polkam.go.id",
        provider: "Coordinating Ministry For Political, Legal, and Security Affairs of Indonesia",
        site: "test-ipv6.polkam.go.id",
        v4: "http://ipv4.test-ipv6.polkam.go.id/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.polkam.go.id/images-nc/knob_green.png"
    },
    "test-ipv6.ro": {
        hide: "0",
        loc: "RO",
        mirror: "1",
        monitor: "Liviu Pislaru <liviu.pislaru@rcs-rds.ro>",
        provider: "RCS & RDS",
        site: "test-ipv6.ro",
        v4: "http://ipv4.test-ipv6.ro/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.ro/images-nc/knob_green.png"
    },
    "test-ipv6.roedu.net": {
        hide: "0",
        loc: "RO",
        mirror: "1",
        monitor: "IPv6 @ RoEduNet <ipv6@roedu.net>",
        provider: "RoEduNet",
        site: "test-ipv6.roedu.net",
        v4: "http://ipv4.test-ipv6.roedu.net/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.roedu.net/images-nc/knob_green.png"
    },
    "test-ipv6.se": {
        hide: "0",
        loc: "SE",
        mirror: "1",
        monitor: "torbjorn.eklov@interlan.se <torbjorn.eklov@interlan.se>",
        provider: "Interlan Gefle AB",
        site: "test-ipv6.se",
        v4: "http://ipv4.test-ipv6.se/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.se/images-nc/knob_green.png"
    },
    "test-ipv6.showmyip.ca": {
        hide: "0",
        loc: "UK",
        mirror: "1",
        monitor: "Christopher Munz-Michielin <christopher@showmyip.ca>",
        provider: "Christopher Munz-Michielin",
        site: "test-ipv6.showmyip.ca",
        v4: "http://ipv4.test-ipv6.showmyip.ca/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.showmyip.ca/images-nc/knob_green.png"
    },
    "test-ipv6.si": {
        hide: "0",
        loc: "SI",
        mirror: "1",
        monitor: "Damjan Sirnik <damjan@sirnik.si>",
        provider: "Damjan Sirnik",
        site: "test-ipv6.si",
        v4: "http://ipv4.test-ipv6.si/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.si/images-nc/knob_green.png"
    },
    "test-ipv6.sjc.vr.org": {
        hide: "0",
        loc: "US CA",
        mirror: "1",
        monitor: "jfesler@gigo.com",
        provider: "vr.org",
        site: "test-ipv6.sjc.vr.org",
        v4: "http://ipv4.test-ipv6.sjc.vr.org/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.sjc.vr.org/images-nc/knob_green.png"
    },
    "test-ipv6.tld.sk": {
        hide: "0",
        loc: "SK",
        mirror: "1",
        monitor: "SK-NIC, a.s. <hostmaster@sk-nic.sk>",
        provider: "Sk-nic",
        site: "test-ipv6.tld.sk",
        v4: "http://ipv4.test-ipv6.tld.sk/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.tld.sk/images-nc/knob_green.png"
    },
    "test-ipv6.tokyo.gigo.com": {
        hide: "0",
        loc: "JP",
        mirror: "1",
        provider: "Jason Fesler (@linode Tokyo)",
        site: "test-ipv6.tokyo.gigo.com",
        v4: "http://ipv4.test-ipv6.tokyo.gigo.com/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.tokyo.gigo.com/images-nc/knob_green.png"
    },
    "test-ipv6.vtt.net": {
        hide: "0",
        loc: "RU",
        mirror: "1",
        monitor: "VTT Network Operations Centre <noc@vtt.net>",
        provider: 'JSC "Volgatranstelecom"',
        site: "test-ipv6.vtt.net",
        v4: "http://ipv4.test-ipv6.vtt.net/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.vtt.net/images-nc/knob_green.png"
    },
    "test-ipv6.vyncke.org": {
        hide: "0",
        loc: "FR",
        mirror: "1",
        monitor: "Eric Vyncke <eric@vyncke.org>",
        provider: "Éric Vyncke",
        site: "test-ipv6.vyncke.org",
        v4: "http://ipv4.test-ipv6.vyncke.org/images-nc/knob_green.png",
        v6: "http://ipv6.test-ipv6.vyncke.org/images-nc/knob_green.png"
    },
    "testipv6.de": {
        hide: "0",
        loc: "DE",
        mirror: "1",
        monitor: "COSIMO WebTeam <kontakt@testipv6.de>",
        provider: "COSIMO Vertriebs -und Beratungs GmbH",
        site: "testipv6.de",
        v4: "http://ipv4.testipv6.de/images-nc/knob_green.png",
        v6: "http://ipv6.testipv6.de/images-nc/knob_green.png"
    },
    "www.ctbc.com.br": {
        hide: "0",
        loc: "BR",
        provider: "Algar Telecom / CTBC",
        site: "www.ctbc.com.br",
        v4: "http://ipv4only.ctbc.net.br/ctbc/pixel.gif",
        v6: "http://ipv6only.ctbc.net.br/ctbc/pixel.gif"
    },
    "www.duiadns.net": {
        loc: "NL",
        mirror: "0",
        monitor: "Liviu Pislaru <liviu.pislaru@duiadns.net>",
        provider: "Duiadns",
        site: "www.duiadns.net",
        v4: "http://ipv4.duiadns.net/1x1.gif",
        v6: "http://ipv6.duiadns.net/1x1.gif"
    },
    "www.excathedra.co": {
        hide: "0",
        loc: "UK",
        monitor: "Steve Durbin <steved@excathedra.co>",
        provider: "Ex Cathedra Photography",
        site: "www.excathedra.co",
        v4: "http://ipv4.excathedra.co/knob_valid_green.png",
        v6: "http://ipv6.excathedra.co/knob_valid_green.png"
    },
    "www.heise.de": {
        hide: "0",
        loc: "DE",
        monitor: "Johannes Endres, c't <je@heise.de>",
        provider: "Heise",
        site: "www.heise.de",
        v4: "http://www.four.heise.de/icons/ho/heise.gif",
        v6: "http://www.six.heise.de/icons/ho/heise.gif"
    },
    "www.radioradicale.it": {
        loc: "IT",
        mirror: "0",
        monitor: "Dario Centofanti <dario@popinga.net>",
        provider: "Centro di Produzione Spa - AS57329",
        site: "www.radioradicale.it",
        v4: "http://ipv4.radioradicale.it/sites/www.radioradicale.it/files/pagine/2015/12/ipv6.png",
        v6: "http://ipv6.radioradicale.it/sites/www.radioradicale.it/files/pagine/2015/12/ipv6.png"
    },
    "www.rascom.ru": {
        loc: "RU",
        provider: "RASCOM",
        site: "www.rascom.ru",
        v4: "http://wood.rascom.ru/ipv4.jpg",
        v6: "http://wood6.rascom.ru/logo2.png"
    },
    "www.rcs-rds.ro": {
        hide: "0",
        loc: "RO",
        monitor: "Liviu Pislaru <liviu.pislaru@rcs-rds.ro>",
        provider: "RCS & RDS",
        site: "www.rcs-rds.ro",
        v4: "http://ipv4.rcs-rds.ro/1x1.gif",
        v6: "http://ipv6.rcs-rds.ro/1x1.gif"
    },
    "www.steffann.nl": {
        hide: "0",
        loc: "NL",
        monitor: "Sander Steffann <sander@steffann.nl>",
        provider: "SJM Steffann Consultancy",
        site: "www.steffann.nl",
        v4: "http://v4-only.steffann.nl/v4-only.png",
        v6: "http://v6-only.steffann.nl/v6-only.png"
    },
    "www.vyncke.org/ipv6status/": {
        hide: "0",
        loc: "FR",
        monitor: "Eric Vyncke <eric@vyncke.org>",
        provider: "Eric Vyncke (personal)",
        site: "www.vyncke.org/ipv6status/",
        v4: "http://test4.vyncke.org/knob_valid_green.png",
        v6: "http://test6.vyncke.org/knob_valid_green.png"
    },
    "www.yahoo.com": {
        hide: "0",
        loc: "global",
        provider: "Yahoo!",
        site: "www.yahoo.com",
        v4: "http://v4test.yahoo.com/eng/test/eye-test.png",
        v6: "http://v6test.yahoo.com/eng/test/eye-test.png"
    },
    "zeop.re": {
        hide: "0",
        loc: "RE",
        monitor: "PAYET Fabien <fabienpayet@zeop.re>",
        provider: "ZEOP",
        site: "zeop.re",
        v4: "http://test-ipv4.zeop.re/ipv4/ipv4.png",
        v6: "http://test-ipv6.zeop.re/ipv6/ipv6.png"
    }
};

GIGO.sites_image_size = 24;

GIGO.url_to_hash = function(url) {
    var hash;
    url = url.replace(/\?nocache.*$/, "");
    hash = jQuery.md5(url);
    hash = hash.replace(/[^a-zA-Z0-9]/g, "");
    hash = hash.substring(0, 4);
    return hash;
};

GIGO.fail_url = function(url) {
    var hash = GIGO.url_to_hash(url);
    if (!GIGO.isdef(GIGO.failed_sites)) {
        GIGO.failed_sites = [];
    }
    if (GIGO.failed_sites.indexOf(hash) < 0) {
        GIGO.failed_sites.push(hash);
    }
    GIGO.show_share_link();
};

GIGO.was_failed_url = function(url) {
    var hash = GIGO.url_to_hash(url);
    if (!GIGO.isdef(GIGO.failed_sites)) {
        if (GIGO.isdef(GIGO.CGI.failed_sites)) {
            GIGO.failed_sites = GIGO.CGI.failed_sites.split(",");
        } else {
            GIGO.failed_sites = [];
        }
    }
    return GIGO.failed_sites.indexOf(hash) >= 0;
};

GIGO.is_replay = function() {
    return GIGO.CGI.ip4 || GIGO.CGI.ip6;
};

GIGO.sites_table_init_1 = function(mode) {
    var newhtml;
    newhtml = '<div id="sitestablediv">';
    newhtml = newhtml + '<table summary="sites" id="sites" class="tablesorter">';
    newhtml = newhtml + "<thead><tr><th>link</th><th>location</th><th>provider</th><th>ipv6?</th><th>info</th></tr></thead>";
    newhtml = newhtml + "<tbody>";
    newhtml = newhtml + "</tbody></table>";
    newhtml = newhtml + "</div>";
    jQuery("#sitestablediv").replaceWith($("<div>").html(newhtml));
};

GIGO.sites_table_init_2 = function(mode) {
    var newhtml;
    newhtml = '<div id="sitestablediv">';
    newhtml = newhtml + '<table summary="sites" id="sites" class="tablesorter">';
    newhtml = newhtml + "<thead><tr><th>link</th><th>location</th><th>provider</th><th>ipv6?</th><th>info</th><th>mirror</th></tr></thead>";
    newhtml = newhtml + "<tbody>";
    newhtml = newhtml + "</tbody></table>";
    newhtml = newhtml + "</div>";
    jQuery("#sitestablediv").replaceWith($("<div>").html(newhtml));
};

GIGO.sites_table_init = function(mode) {
    if (mode === 1) {
        GIGO.sites_table_init_1(mode);
    } else if (mode === 2) {
        GIGO.sites_table_init_2(mode);
    } else {
        alert("bad GIGO.sites_table_init()");
    }
};

GIGO.sites_table_populate_1 = function(mode) {
    var i;
    for (i = 0; i < GIGO.sites_queue.length; i = i + 1) {
        GIGO.sites_display_add_record(GIGO.sites_queue[i], mode);
    }
    $("#sites").tablesorter({
        textExtraction: "complex",
        sortInitialOrder: "asc",
        headers: {
            0: {
                sorter: "text"
            },
            1: {
                sorter: "text"
            },
            2: {
                sorter: "text"
            },
            3: {
                sorter: "text"
            },
            4: {
                sorter: "text"
            },
            5: {
                sorter: false
            },
            6: {
                sorter: false
            }
        }
    });
};

GIGO.sites_table_populate_2 = function(mode) {
    var i;
    for (i = 0; i < GIGO.sites_queue.length; i = i + 1) {
        GIGO.sites_display_add_record(GIGO.sites_queue[i], mode);
    }
    $("#sites").tablesorter({
        textExtraction: "complex",
        sortInitialOrder: "asc",
        headers: {
            0: {
                sorter: "text"
            },
            1: {
                sorter: "text"
            },
            2: {
                sorter: "text"
            },
            3: {
                sorter: false
            },
            4: {
                sorter: false
            }
        }
    });
};

GIGO.sites_table_populate = function(mode) {
    if (mode === 1) {
        GIGO.sites_table_populate_1(mode);
    } else if (mode === 2) {
        GIGO.sites_table_populate_2(mode);
    } else {
        alert("bad GIGO.sites_table_populate()");
    }
};

GIGO.sites_init = function() {
    GIGO.sites_queue = [];
};

GIGO.sites_queue_entry = function(r) {
    if (!r.v4) {
        r.v4 = "ipv4." + r.site + "/images-nc/knob_valid_green.png";
    }
    if (!r.v6) {
        r.v6 = "ipv6." + r.site + "/images-nc/knob_valid_green.png";
    }
    if (r.v4.search(/\?/) < 0) {
        r.v4 = r.v4 + "?";
    }
    if (r.v6.search(/\?/) < 0) {
        r.v6 = r.v6 + "?";
    }
    try {
        r.v4 = r.v4 + "&testdomain=" + GIGO.options.domain;
        r.v6 = r.v6 + "&testdomain=" + GIGO.options.domain;
    } catch (e) {
        r.v4 = r.v4 + "&testdomain=" + document.location.hostname;
        r.v6 = r.v6 + "&testdomain=" + document.location.hostname;
    }
    r.v4 = r.v4 + "&testname=sites";
    r.v6 = r.v6 + "&testname=sites";
    GIGO.sites_queue.push(r);
};

GIGO.sites_queue_all = function(mode) {
    var r, siteName;
    for (siteName in GIGO.sites_parsed) {
        r = GIGO.sites_parsed[siteName];
        if (mode === 1) {
            if (!r.mirror) continue;
            if (!parseInt(r.mirror)) continue;
        }
        GIGO.sites_queue_entry(r);
    }
};

GIGO.sites_prepare_helpdesk = function(mode) {
    GIGO.helpdesk.other_sites = {};
    GIGO.helpdesk.other_sites.finished = 0;
    GIGO.helpdesk.other_sites.count = 0;
    GIGO.helpdesk.other_sites.good = [];
    GIGO.helpdesk.other_sites.bad = [];
    if (mode > 1) {
        GIGO.helpdesk.other_sites.count = GIGO.sites_queue.length;
    }
};

GIGO.other_sites_info = function() {
    var g, b, f, c, o, text;
    g = GIGO.helpdesk.other_sites.good.length;
    b = GIGO.helpdesk.other_sites.bad.length;
    f = GIGO.helpdesk.other_sites.finished;
    c = GIGO.helpdesk.other_sites.count;
    o = g + b;
    text = "";
    if (!c) {
        return "";
    }
    if (f != c) {
        text = "(Global IPv6 connectivity being tested; " + f + "/" + c + ")";
        return text;
    }
    text = "OtherSites: " + g + "/" + o + " good";
    if (b) {
        text = text + ", " + b + "/" + o + " bad";
    }
    return text;
};

GIGO.other_sites_failures = function() {
    var div, table, i;
    if (!GIGO.helpdesk.other_sites.bad.length) {
        return jQuery("<div>");
    }
    div = jQuery("<div>");
    div.append(jQuery("<p><span style='color: red'>Site(s) with failed connectivity</p>"));
    table = jQuery("<table>");
    table.append(jQuery("<tr><td>Site</td><td>Failed URL</td></tr>"));
    for (i = 0; i < GIGO.helpdesk.other_sites.bad.length; i = i + 1) {
        table.append(GIGO.sites_display_bad_r_to_tr(GIGO.helpdesk.other_sites.bad[i]));
    }
    div.append(table);
    return div;
};

GIGO.sites_display_bad_r_to_tr = function(r) {
    var tr, a, parts;
    tr = jQuery("<tr>");
    parts = r.v6.split("/");
    tr.append(jQuery("<td>").text(parts[0]));
    a = jQuery("<a>");
    a.text(r.v6);
    a.attr("href", r.v6);
    a.attr("target", "_blank");
    tr.append(jQuery("<td>").append(a));
    return tr;
};

GIGO.sites_display_td_provider_div_update = function(r) {
    var i, td_provider_div;
    td_provider_div = r.refs.td_provider_div;
    td_provider_div.text(r.provider);
    for (i in arguments) {
        if (i > 0) {
            td_provider_div.append("<br/>");
            td_provider_div.append(arguments[i]);
        }
    }
};

GIGO.sites_display_add_record = function(r, mode) {
    var tr, td_link, td_loc, td_provider, td_status, td_info, td_mirror, mirror_button, site, td_provider_div;
    site = $("<a>", {
        text: r.site,
        href: "http://" + r.site,
        target: r.site
    });
    tr = $("<tr></tr>");
    td_link = $("<td>").append(site);
    td_loc = $("<td>").text(r.loc);
    td_provider_div = $("<div>").text(r.provider);
    td_provider = $("<td>").append(td_provider_div);
    td_status = $("<td>").append($("<img>", {
        src: "/images/spinner.gif",
        height: GIGO.sites_image_size,
        width: GIGO.sites_image_size
    }).css("opacity", "0.1").css("filter", "alpha(opacity=10)"));
    td_info = $("<td>").append($("<img>", {
        src: "/images/knob_info.png",
        height: GIGO.sites_image_size,
        width: GIGO.sites_image_size
    }));
    td_info.click(function() {
        GIGO.sites_display_td_provider_div_update(r, $("<a>", {
            text: r.v4,
            href: r.v4,
            target: "_blank"
        }), $("<a>", {
            text: r.v6,
            href: r.v6,
            target: "_blank"
        }));
    });
    if (mode === 2 && r.mirror && parseInt(r.mirror)) {
        mirror_button = $("<a target='" + r.site + "' href='http://" + r.site + "'><img border=0 src='/images/knob_play.png'/></a>");
        mirror_button.find("img").attr("width", GIGO.sites_image_size);
        mirror_button.find("img").attr("height", GIGO.sites_image_size);
        td_mirror = $("<td>").append(mirror_button);
    } else {
        td_mirror = $("<td>").html("&nbsp;");
    }
    if (mode === 1) {
        tr.append(td_link, td_loc, td_provider, td_status, td_info);
    } else if (mode === 2) {
        tr.append(td_link, td_loc, td_provider, td_status, td_info, td_mirror);
    } else {
        return;
    }
    $("#sites > tbody:last").append(tr);
    $("#sites").find("tbody:last").append(tr);
    r.refs = {};
    r.refs.tr = tr;
    r.refs.td_link = td_link;
    r.refs.td_loc = td_loc;
    r.refs.td_provider = td_provider;
    r.refs.td_provider_div = td_provider_div;
    r.refs.td_status = td_status;
    r.refs.td_info = td_info;
    r.refs.td_mirror = td_mirror;
};

GIGO.sites_display_success = function(r) {
    var new_td;
    new_td = $("<td>").append($("<img>", {
        src: "/images/knob_valid_green.png",
        height: GIGO.sites_image_size,
        width: GIGO.sites_image_size
    }));
    r.refs.td_status.replaceWith(new_td);
    GIGO.helpdesk.other_sites.finished = GIGO.helpdesk.other_sites.finished + 1;
    GIGO.helpdesk.other_sites.good.push(r);
    GIGO.sites_update_helpdesk();
};

GIGO.sites_display_failure = function(r) {
    var new_td;
    new_td = $("<td>").append($("<img>", {
        src: "/images/knob_cancel.png",
        height: GIGO.sites_image_size,
        width: GIGO.sites_image_size
    }));
    r.refs.td_status.replaceWith(new_td);
    GIGO.helpdesk.other_sites.finished = GIGO.helpdesk.other_sites.finished + 1;
    GIGO.helpdesk.other_sites.bad.push(r);
    GIGO.sites_update_helpdesk();
};

GIGO.sites_display_giveup = function(r) {
    var new_td;
    new_td = $("<td>").append($("<img>", {
        src: "/images/knob_graphite.png",
        height: GIGO.sites_image_size,
        width: GIGO.sites_image_size
    }));
    r.refs.td_status.replaceWith(new_td);
    GIGO.sites_display_td_provider_div_update(r, "IPv4 site down, skipping IPv6 test");
    GIGO.helpdesk.other_sites.finished = GIGO.helpdesk.other_sites.finished + 1;
    GIGO.sites_update_helpdesk();
};

GIGO.sites_update_helpdesk = function() {
    if (GIGO.helpdesk.other_sites.count) {
        GIGO.finish_helpdesk();
    }
};

GIGO.sites_start_ipv6_take2 = function(r) {
    var url, img, img_pending;
    if (!r.v6) {
        return;
    }
    url = r.v6 + "?nocache=" + Math.random();
    if (GIGO.is_replay()) {
        img_pending = 0;
        if (GIGO.was_failed_url(url)) {
            GIGO.fail_url(url);
            GIGO.sites_display_failure(r);
        } else {
            GIGO.sites_display_success(r);
        }
        GIGO.sites_next_in_queue();
        return;
    }
    setTimeout(function() {
        img = jQuery('<img style="display:none" />');
        img_pending = 1;
        jQuery(img).bind({
            load: function() {
                if (img_pending) {
                    img_pending = 0;
                    GIGO.sites_display_success(r);
                    GIGO.sites_next_in_queue();
                }
            },
            error: function() {
                if (img_pending) {
                    img_pending = 0;
                    GIGO.fail_url(url);
                    GIGO.sites_display_failure(r);
                    GIGO.sites_next_in_queue();
                }
            }
        });
        setTimeout(function() {
            if (img_pending) {
                img_pending = 0;
                GIGO.fail_url(url);
                GIGO.sites_display_failure(r);
                GIGO.sites_next_in_queue();
            }
        }, GIGO.max_time);
        jQuery(img).attr("src", url);
    }, 1e3);
};

GIGO.sites_start_ipv6 = function(r) {
    var url, img, img_pending;
    if (!r.v6) {
        return;
    }
    if (GIGO.is_replay()) {
        GIGO.sites_start_ipv6_take2(r);
        return;
    }
    url = r.v6 + "?nocache=" + Math.random();
    img = jQuery('<img style="display:none" />');
    img_pending = 1;
    jQuery(img).bind({
        load: function() {
            if (img_pending) {
                img_pending = 0;
                GIGO.sites_display_success(r);
                GIGO.sites_next_in_queue();
            }
        },
        error: function() {
            if (img_pending) {
                img_pending = 0;
                GIGO.sites_start_ipv6_take2(r);
            }
        }
    });
    setTimeout(function() {
        if (img_pending) {
            img_pending = 0;
            GIGO.sites_start_ipv6_take2(r);
        }
    }, GIGO.max_time);
    jQuery(img).attr("src", url);
};

GIGO.sites_start_ipv4_take2 = function(r) {
    var url, img, img_pending;
    if (!r.v4) {
        return;
    }
    url = r.v4 + "?nocache=" + Math.random();
    if (GIGO.is_replay()) {
        img_pending = 0;
        if (GIGO.was_failed_url(url)) {
            GIGO.fail_url(url);
            GIGO.sites_display_giveup(r);
        } else {
            GIGO.sites_start_ipv6(r);
        }
        GIGO.sites_next_in_queue();
        return;
    }
    setTimeout(function() {
        r.refs.td_status.find("img").css("opacity", "1.0").css("filter", "alpha(opacity=100)");
        img = jQuery('<img style="display:none" />');
        img_pending = 1;
        jQuery(img).bind({
            load: function() {
                img_pending = 0;
                GIGO.sites_start_ipv6(r);
            },
            error: function() {
                if (img_pending) {
                    img_pending = 0;
                    GIGO.fail_url(url);
                    GIGO.sites_display_giveup(r);
                    GIGO.sites_next_in_queue();
                }
            }
        });
        setTimeout(function() {
            if (img_pending) {
                img_pending = 0;
                GIGO.fail_url(url);
                GIGO.sites_display_giveup(r);
                GIGO.sites_next_in_queue();
            }
        }, GIGO.max_time);
        jQuery(img).attr("src", url);
    }, 1e3);
};

GIGO.sites_start_ipv4 = function(r) {
    var url, img, img_pending;
    if (!r.v4) {
        return;
    }
    if (!GIGO.results.ipv4.ip && GIGO.results.ipv6.ip) {
        GIGO.sites_start_ipv6(r);
        return;
    }
    if (GIGO.is_replay()) {
        GIGO.sites_start_ipv4_take2(r);
        return;
    }
    r.refs.td_status.find("img").css("opacity", "1.0").css("filter", "alpha(opacity=100)");
    url = r.v4 + "?nocache=" + Math.random();
    img = jQuery('<img style="display:none" />');
    img_pending = 1;
    jQuery(img).bind({
        load: function() {
            if (img_pending) {
                img_pending = 0;
                GIGO.sites_start_ipv6(r);
            }
        },
        error: function() {
            if (img_pending) {
                img_pending = 0;
                GIGO.sites_start_ipv4_take2(r);
            }
        }
    });
    setTimeout(function() {
        if (img_pending) {
            img_pending = 0;
            GIGO.sites_start_ipv4_take2(r);
        }
    }, GIGO.max_time);
    jQuery(img).attr("src", url);
};

GIGO.sites_next_in_queue = function() {
    var r;
    if (GIGO.sites_queue.length > 0) {
        r = GIGO.sites_queue.shift();
        GIGO.sites_start_ipv4(r);
    }
};

GIGO.sites_start_tests = function() {
    if (0 && GIGO.is_replay()) {
        while (GIGO.sites_queue.length > 0) {
            GIGO.sites_next_in_queue();
        }
    } else {
        setTimeout(GIGO.sites_next_in_queue, 1);
        setTimeout(GIGO.sites_next_in_queue, 75);
        setTimeout(GIGO.sites_next_in_queue, 150);
        setTimeout(GIGO.sites_next_in_queue, 225);
        setTimeout(GIGO.sites_next_in_queue, 300);
        setTimeout(GIGO.sites_next_in_queue, 375);
        setTimeout(GIGO.sites_next_in_queue, 450);
        setTimeout(GIGO.sites_next_in_queue, 525);
        setTimeout(GIGO.sites_next_in_queue, 600);
    }
};

GIGO.test_sites = function(mode) {
    GIGO.sites_init(mode);
    GIGO.sites_queue_all(mode);
    GIGO.fisherYates(GIGO.sites_queue);
    GIGO.sites_prepare_helpdesk(mode);
    GIGO.sites_table_init(mode);
    GIGO.sites_table_populate(mode);
    GIGO.sites_start_tests(mode);
};

GIGO.fisherYates = function(myArray) {
    var i, j, tempi, tempj;
    i = myArray.length;
    if (i === 0) {
        return;
    }
    while (i > 0) {
        i = i - 1;
        j = Math.floor(Math.random() * (i + 1));
        tempi = myArray[i];
        tempj = myArray[j];
        myArray[i] = tempj;
        myArray[j] = tempi;
    }
};

GIGO.start_helpdesk = function() {
    var want_helpdesk = 0;
    if (GIGO.CGI.isp) {
        want_helpdesk = 1;
    }
    if (GIGO.CGI.helpdesk) {
        want_helpdesk = 1;
    }
    if (String(location.pathname).match(/\b(isp|helpdesk)\b/i)) {
        want_helpdesk = 1;
    }
    if (String(location.hostname).match(/\b(isp|helpdesk)\b/i)) {
        want_helpdesk = 1;
    }
    if (String(location.hash).match(/^(isp|helpdesk)\$/i)) {
        want_helpdesk = 1;
    }
    if (want_helpdesk) {
        GIGO.tabnav("helpdesk");
    } else {
        $("#tabbutton_helpdesk_link").addClass("navright");
    }
};

GIGO.helpdesk_ob_status = function(n) {
    var s = GIGO.results.tests[n].status;
    if (s === "ok") return "g";
    if (s === "slow") return "g";
    if (s === "bad") return "b";
    if (s === "timeout") return "t";
};

GIGO.helpdesk_ob_type = function() {
    var t = "b";
    if (GIGO.results.ipv6 && GIGO.results.ipv6.ip) {
        t = "g";
        if (GIGO.helpdesk.teredo) {
            t = "t";
        }
        if (GIGO.helpdesk.sixfour) {
            t = "6";
        }
        if (GIGO.helpdesk.tunnel) {
            t = "a";
        }
    }
    return t;
};

GIGO.helpdesk_score = function() {
    var mini_helpdesk, score;
    var status_a = GIGO.helpdesk_ob_status("test_a");
    var status_ipv4 = GIGO.helpdesk_ob_status("test_ipv4");
    var status_aaaa = GIGO.helpdesk_ob_status("test_aaaa");
    var status_ipv6_type = GIGO.helpdesk_ob_type();
    var status = status_a + status_ipv4 + ":" + status_aaaa + status_ipv6_type;
    var ob = new Object();
    ob.found = GIGO.sym_helpdesk[status];
    ob.qcode = GIGO.sym_helpdesk_qcode[ob.found];
    if (ob.found) {
        if (GIGO.helpdesk.failed_pmtud) {
            ob.found = ob.found + ", Potential MTU issues";
            ob.qcode = ob.qcode + ",mtu";
        }
        if (GIGO.helpdesk.mini_primary.match(/s/)) {
            ob.found = ob.found + ", Slow";
            ob.qcode = ob.qcode + ",slow";
        }
        return ob;
    }
    return;
};

GIGO.helpdesk_good_bad_slow = function(a) {
    var slow = 0;
    var good = 0;
    var tout = 0;
    var i = 0;
    for (i = 0; i < a.length; i = i + 1) {
        if (GIGO.results.tests[a[i]].status === "ok") {
            good = 1;
        }
        if (GIGO.results.tests[a[i]].status === "slow") {
            slow = 1;
        }
        if (GIGO.results.tests[a[i]].status === "timeout") {
            tout = 1;
        }
    }
    if (tout) return "Timeout";
    if (slow) return "Slow";
    if (good) return "Good";
    return "Bad";
};

GIGO.helpdesk_ipv4_info = function() {
    var test_a, test_asn4, s;
    test_a = GIGO.results.tests.test_a;
    test_asn4 = GIGO.results.tests.test_asn4;
    if (test_a.ipinfo && test_a.ipinfo.ip) {
        s = "IPv4: ";
        s = s + GIGO.helpdesk_good_bad_slow([ "test_a", "test_ds4", "test_ipv4" ]);
        if (test_asn4.ipinfo && test_asn4.ipinfo.asn) {
            s = s + ", AS" + test_asn4.ipinfo.asn + " - ";
            s = s + test_asn4.ipinfo.asn_name;
        }
        return s;
    } else {
        return "IPv4: no";
    }
};

GIGO.helpdesk_ipv6_info = function() {
    var test_aaaa, test_asn6, s;
    test_aaaa = GIGO.results.tests.test_aaaa;
    test_asn6 = GIGO.results.tests.test_asn6;
    if (test_aaaa.ipinfo && test_aaaa.ipinfo.ip) {
        s = "IPv6: ";
        s = s + GIGO.helpdesk_good_bad_slow([ "test_aaaa", "test_ds6", "test_ipv6", "test_v6mtu" ]);
        if (test_asn6.ipinfo && test_asn6.ipinfo.asn) {
            s = s + ", AS" + test_asn6.ipinfo.asn + " - ";
            s = s + test_asn6.ipinfo.asn_name;
        }
        return s;
    } else {
        if (GIGO.results.tests.test_aaaa && GIGO.results.tests.test_aaaa.status && GIGO.results.tests.test_aaaa.status === "timeout") {
            return "IPv6: broken";
        }
        if (GIGO.results.tests.test_ds && GIGO.results.tests.test_ds.status && GIGO.results.tests.test_ds.status === "timeout") {
            return "IPv6: broken";
        }
        if (GIGO.results.tests.test_ipv6 && GIGO.results.tests.test_ipv6.status && GIGO.results.tests.test_ipv6.status === "timeout") {
            return "IPv6: broken";
        }
        return "IPv6: no";
    }
};

GIGO.finish_helpdesk = function() {
    var code, div;
    if (!GIGO.results.debug_code) {
        return;
    }
    jQuery("#replayurldiv").show();
    code = GIGO.helpdesk_score();
    div = jQuery("<div>", {
        id: "helpdesk_content"
    });
    div.append(jQuery("<p>").append("Your Internet help desk may ask you for the information below."));
    if (code && code.qcode) {
        div.append(jQuery("<p>").append(jQuery("<span class=helpdeskcode>").text("Help desk code: " + code.qcode)));
    }
    if (code && code.found) {
        div.append(jQuery("<p>").append(jQuery("<b>").text(code.found)));
    }
    div.append(jQuery("<div>").text(GIGO.helpdesk_ipv4_info()));
    div.append(jQuery("<div>").text(GIGO.helpdesk_ipv6_info()));
    if (GIGO.helpdesk.other_sites && GIGO.helpdesk.other_sites.count) {
        div.append(jQuery("<div>").text(GIGO.other_sites_info()));
    }
    div.append("<div><p></p></div>");
    if (GIGO.results.ipv4 && GIGO.results.ipv4.ip) {
        div.append(jQuery("<div>").text("IPv4 address: " + GIGO.results.ipv4.ip));
    }
    if (GIGO.results.ipv6 && GIGO.results.ipv6.ip) {
        div.append(jQuery("<div>").text("IPv6 address: " + GIGO.results.ipv6.ip));
    }
    div.append("<div><p></p></div>");
    if (GIGO.helpdesk.other_sites) {
        div.append(GIGO.other_sites_failures());
    }
    $("#helpdesk_content").replaceWith(div);
};

GIGO.pulse_background_speed = 250;

GIGO.pulse_background_colors = [ "#fffeee", "#fffeee", "#fffddd", "#fffccc", "#fffbbb", "#fffbbb", "#fffccc", "#fffddd", "#fffeee", "#fffeee" ];

GIGO.pulse_on = function() {
    var n = GIGO.pulse_background_colors.shift();
    GIGO.pulse_background_colors.push(n);
    jQuery(".help_popup").css("background-color", n);
    jQuery("#comments_faq_link").css("background-color", n);
    setTimeout(function() {
        GIGO.pulse_on();
    }, GIGO.pulse_background_speed);
};

GIGO.prepare_fake = function() {
    var i, funcname, shortname;
    for (i = 0; i < GIGO.queue.length; i = i + 1) {
        funcname = GIGO.queue[i][2];
        shortname = funcname.replace(/^test_/, "");
        if (GIGO.CGI[shortname]) {
            GIGO.override = 1;
            GIGO.overrides[funcname] = GIGO.CGI[shortname];
            GIGO.use_queue = 1;
        }
    }
    if (GIGO.isdef(GIGO.CGI.ip4) || GIGO.isdef(GIGO.CGI.ip6)) {
        GIGO.override = 1;
    }
};

GIGO.override_id = function(id, url) {
    var tests, this_test, parts, status, protocol, whichasn;
    tests = GIGO.results.tests;
    if (!tests.hasOwnProperty(id)) {
        tests[id] = {};
    }
    tests[id] = {};
    this_test = tests[id];
    this_test.url = url;
    this_test.start_time = GIGO.getms();
    this_test.ipinfo = {};
    GIGO.update_url(id);
    parts = GIGO.overrides[id].split(/,/);
    status = parts[0];
    protocol = parts[2];
    if (!protocol) {
        if (id === "test_aaaa" || id === "test_ipv6" || id === "test_v6mtu" || id === "test_v6ns" || id === "test_dsmtu" || id === "test_ds") {
            protocol = "ipv6";
        } else {
            protocol = "ipv4";
        }
    }
    whichasn = "test_asn" + protocol.replace(/^ipv/, "");
    if (status === "ok") {
        for (var key in tests[whichasn].ipinfo) {
            if (!key.match(/^asn/)) {
                this_test.ipinfo[key] = tests[whichasn].ipinfo[key];
            }
        }
        this_test.status = status;
        this_test.time_ms = parseInt(parts[1]) || 1;
    }
    if (status === "slow") {
        for (var key in tests[whichasn].ipinfo) {
            if (!key.match(/^asn/)) {
                this_test.ipinfo[key] = tests[whichasn].ipinfo[key];
            }
        }
        this_test.status = status;
        this_test.time_ms = parseInt(parts[1]) || GIGO.slow + 1;
    }
    if (status === "bad") {
        this_test.ipinfo = {};
        this_test.status = status;
        this_test.time_ms = parseInt(parts[1]) || 1;
    }
    if (status === "timeout") {
        this_test.ipinfo = {};
        this_test.status = status;
        this_test.time_ms = parseInt(parts[1]) || GIGO.max_time + 1;
    }
    if (id === "test_ds") {
        if (this_test.ipinfo.type === "ipv6") {
            tests.test_ds6 = {
                url: this_test.url,
                time_ms: this_test.time_ms,
                status: this_test.status
            };
            tests.test_ds4 = {
                url: this_test.url,
                time_ms: this_test.time_ms,
                status: "bad"
            };
        } else {
            tests.test_ds4 = {
                url: this_test.url,
                time_ms: this_test.time_ms,
                status: this_test.status
            };
            tests.test_ds6 = {
                url: this_test.url,
                time_ms: this_test.time_ms,
                status: "bad"
            };
        }
    }
};

GIGO.override_id_ip = function(id) {
    var tests, this_test, parts, status, protocol, whichasn;
    tests = GIGO.results.tests;
    this_test = tests[id];
    if (!this_test) {
        return;
    }
    if (!this_test.ipinfo.type) {
        return;
    }
    whichasn = "test_asn" + this_test.ipinfo.type.replace(/^ipv/, "");
    this_test.ipinfo = {};
    for (var key in tests[whichasn].ipinfo) {
        if (!key.match(/^asn/)) {
            this_test.ipinfo[key] = tests[whichasn].ipinfo[key];
        }
    }
};

GIGO.update_ipaddress = function(ipinfo) {
    if (ipinfo.type === "ipv4") {
        if (!GIGO.results.ipv4.asn) {
            GIGO.results.ipv4 = ipinfo;
        }
    }
    if (ipinfo.type === "ipv6") {
        if (!GIGO.results.ipv6.asn) {
            GIGO.results.ipv6 = ipinfo;
        }
    }
};

GIGO.test_type_delayed = function(url, id) {
    GIGO.slowcount = GIGO.slowcount + 1;
    setTimeout(function() {
        GIGO.test_type(url, id);
    }, GIGO.slowcount * GIGO.slowcount_delay);
};

GIGO.finish_test = function(id) {
    var total_tests = GIGO.queue.length + GIGO.dequeued.length;
    GIGO.tests_finished = GIGO.tests_finished + 1;
    GIGO.update_progress(GIGO);
    GIGO.update_status(id);
    if (GIGO.tests_finished >= total_tests) {
        GIGO.check_results();
    }
    GIGO.next_in_queue();
    GIGO.show_debug();
};

GIGO.test_type_json = function(url, id) {
    var tests, this_test;
    if (url.search(/\?/) < 0) {
        url = url + "?";
    }
    url = url + "&testdomain=" + GIGO.options.domain;
    url = url + "&testname=" + id;
    if (Browser.opera) {
        url = url + "&random=" + Math.random();
    }
    tests = GIGO.results.tests;
    if (!tests.hasOwnProperty(id)) {
        tests[id] = {};
    }
    this_test = tests[id];
    this_test.start_time = GIGO.getms();
    this_test.url = url;
    if (GIGO.overrides && GIGO.overrides[id]) {
        GIGO.override_id(id, url);
        GIGO.finish_test(id);
        GIGO.update_url(id);
        GIGO.show_debug();
        return;
    }
    GIGO.update_url(id);
    jQuery.jsonp({
        url: url,
        cache: true,
        pageCache: false,
        timeout: GIGO.max_time,
        success: function(ipinfo) {
            var delta;
            delete ipinfo.full;
            this_test.ipinfo = ipinfo;
            if (GIGO.override) {
                GIGO.override_id_ip(id);
            }
            GIGO.update_ipaddress(this_test.ipinfo);
            GIGO.update_ip(id);
            delta = GIGO.getms() - this_test.start_time;
            if (GIGO.isdef(this_test.time_ms)) {
                if (delta < this_test.time_ms) {
                    this_test.time_ms = delta;
                }
            } else {
                this_test.time_ms = delta;
            }
            this_test.status = this_test.time_ms < GIGO.slow ? "ok" : "slow";
            if (id === "test_ds") {
                if (ipinfo.type === "ipv6") {
                    tests.test_ds6 = {
                        url: this_test.url,
                        time_ms: this_test.time_ms,
                        status: this_test.status
                    };
                    tests.test_ds4 = {
                        url: this_test.url,
                        time_ms: this_test.time_ms,
                        status: "bad"
                    };
                } else {
                    tests.test_ds4 = {
                        url: this_test.url,
                        time_ms: this_test.time_ms,
                        status: this_test.status
                    };
                    tests.test_ds6 = {
                        url: this_test.url,
                        time_ms: this_test.time_ms,
                        status: "bad"
                    };
                }
            }
            GIGO.finish_test(id);
        },
        error: function(d, msg) {
            var delta;
            delta = GIGO.getms() - this_test.start_time;
            if (GIGO.isdef(this_test.time_ms)) {
                if (delta < this_test.time_ms) {
                    this_test.time_ms = delta;
                }
            } else {
                this_test.time_ms = delta;
            }
            this_test.status = this_test.time_ms < GIGO.slow ? "bad" : "timeout";
            if (id === "test_ds") {
                tests.test_ds6 = {
                    url: this_test.url,
                    time_ms: this_test.time_ms,
                    status: this_test.status
                };
                tests.test_ds4 = {
                    url: this_test.url,
                    time_ms: this_test.time_ms,
                    status: this_test.status
                };
                GIGO.queue.push([ "test_buggydns1", GIGO.options.url.test_buggydns1_img, "test_buggydns1" ]);
            }
            GIGO.finish_test(id);
            GIGO.queue.push([ "test_type_img", GIGO.options.url[id + "_img"], id + "_img" ]);
        }
    });
    GIGO.update_url(id);
    GIGO.show_debug();
};

GIGO.test_type_json_only = function(url, id) {
    var tests, this_test;
    if (url.search(/\?/) < 0) {
        url = url + "?";
    }
    url = url + "&testdomain=" + GIGO.options.domain;
    url = url + "&testname=" + id;
    if (Browser.opera) {
        url = url + "&random=" + Math.random();
    }
    tests = GIGO.results.tests;
    if (!tests.hasOwnProperty(id)) {
        tests[id] = {};
    }
    this_test = tests[id];
    this_test.start_time = GIGO.getms();
    this_test.url = url;
    GIGO.update_url(id);
    if (id === "test_asn4" && GIGO.isdef(GIGO.CGI.ip4)) {
        if (GIGO.CGI.ip4 && GIGO.CGI.ip4.match(/^[0-9abcdef.:]+$/)) {
            url = "/ip/?callback=?&asn=1&testip=" + GIGO.CGI.ip4;
            url = url + "&testdomain=" + GIGO.options.domain;
            url = url + "&testname=" + id;
            this_test.url = url;
            GIGO.update_url(id);
        } else {
            this_test.ipinfo = {};
            this_test.status = "bad";
            this_test.time_ms = 1;
            GIGO.finish_test(id);
            GIGO.update_url(id);
            GIGO.show_debug();
            return;
        }
    }
    if (id === "test_asn6" && GIGO.isdef(GIGO.CGI.ip6)) {
        if (GIGO.CGI.ip6 && GIGO.CGI.ip6.match(/^[0-9abcdef.:]+$/)) {
            url = "/ip/?callback=?&asn=1&testip=" + GIGO.CGI.ip6;
            url = url + "&testdomain=" + GIGO.options.domain;
            url = url + "&testname=" + id;
            this_test.url = url;
            GIGO.update_url(id);
        } else {
            this_test.ipinfo = {};
            this_test.status = "bad";
            this_test.time_ms = 1;
            GIGO.finish_test(id);
            GIGO.update_url(id);
            GIGO.show_debug();
            return;
        }
    }
    jQuery.jsonp({
        url: url,
        cache: true,
        pageCache: false,
        timeout: GIGO.max_time,
        success: function(ipinfo) {
            var delta;
            delete ipinfo.full;
            this_test.ipinfo = ipinfo;
            GIGO.update_ipaddress(this_test.ipinfo);
            GIGO.update_ip(id);
            delta = GIGO.getms() - this_test.start_time;
            if (GIGO.isdef(this_test.time_ms)) {
                if (delta < this_test.time_ms) {
                    this_test.time_ms = delta;
                }
            } else {
                this_test.time_ms = delta;
            }
            this_test.status = this_test.time_ms < GIGO.slow ? "ok" : "slow";
            GIGO.finish_test(id);
        },
        error: function(d, msg) {
            var delta;
            delta = GIGO.getms() - this_test.start_time;
            if (GIGO.isdef(this_test.time_ms)) {
                if (delta < this_test.time_ms) {
                    this_test.time_ms = delta;
                }
            } else {
                this_test.time_ms = delta;
            }
            this_test.status = this_test.time_ms < GIGO.slow ? "bad" : "timeout";
            GIGO.finish_test(id);
        }
    });
    GIGO.update_url(id);
    GIGO.show_debug();
};

GIGO.test_buggydns1 = function(url, id) {
    var tests, this_test, img, img_pending, max_time;
    jQuery(".optional_buggydns1").show();
    max_time = GIGO.max_time > 5e3 ? 5e3 : GIGO.max_time;
    if (url.search(/\?/) < 0) {
        url = url + "?";
    }
    url = url + "&testdomain=" + GIGO.options.domain;
    url = url + "&testname=" + id;
    if (Browser.opera) {
        url = url + "&random=" + Math.random();
    }
    tests = GIGO.results.tests;
    if (!tests.hasOwnProperty(id)) {
        tests[id] = {};
    }
    this_test = tests[id];
    this_test.start_time = GIGO.getms();
    this_test.url = url;
    GIGO.update_url(id);
    img_pending = 1;
    img = jQuery('<img style="display:none" />');
    jQuery(img).bind({
        load: function() {
            var delta;
            if (img_pending) {
                img_pending = 0;
                delta = GIGO.getms() - this_test.start_time;
                if (GIGO.isdef(this_test.time_ms)) {
                    if (delta < this_test.time_ms) {
                        this_test.time_ms = delta;
                    }
                } else {
                    this_test.time_ms = delta;
                }
                this_test.image = 1;
                this_test.status = "affected";
                GIGO.finish_test(id);
            }
        },
        error: function() {
            var delta;
            if (img_pending) {
                img_pending = 0;
                delta = GIGO.getms() - this_test.start_time;
                if (GIGO.isdef(this_test.time_ms)) {
                    if (delta < this_test.time_ms) {
                        this_test.time_ms = delta;
                    }
                } else {
                    this_test.time_ms = delta;
                }
                this_test.image = 1;
                this_test.status = "safe";
                GIGO.finish_test(id);
            }
        }
    });
    setTimeout(function() {
        var delta;
        if (img_pending) {
            img_pending = 0;
            jQuery(img).attr("src", "/images/knob_red.png");
            delta = GIGO.getms() - this_test.start_time;
            if (GIGO.isdef(this_test.time_ms)) {
                if (delta < this_test.time_ms) {
                    this_test.time_ms = delta;
                }
            } else {
                this_test.time_ms = delta;
            }
            this_test.image = 1;
            this_test.status = "safe";
            GIGO.finish_test(id);
        }
    }, max_time);
    jQuery(img).attr("src", url);
    GIGO.update_url(id);
    GIGO.show_debug();
};

GIGO.test_type_img = function(url, id) {
    var tests, this_test, img, img_pending;
    if (url.search(/\?/) < 0) {
        url = url + "?";
    }
    url = url + "&testdomain=" + GIGO.options.domain;
    url = url + "&testname=" + id;
    if (Browser.opera) {
        url = url + "&random=" + Math.random();
    }
    tests = GIGO.results.tests;
    if (!tests.hasOwnProperty(id)) {
        tests[id] = {};
    }
    this_test = tests[id];
    this_test.start_time = GIGO.getms();
    this_test.url = url;
    GIGO.update_url(id);
    img_pending = 1;
    img = jQuery('<img style="display:none" />');
    jQuery(img).bind({
        load: function() {
            var delta;
            if (img_pending) {
                img_pending = 0;
                delta = GIGO.getms() - this_test.start_time;
                if (GIGO.isdef(this_test.time_ms)) {
                    if (delta < this_test.time_ms) {
                        this_test.time_ms = delta;
                    }
                } else {
                    this_test.time_ms = delta;
                }
                this_test.image = 1;
                this_test.status = this_test.time_ms < GIGO.slow ? "ok" : "slow";
                if (this_test.test_ms > GIGO.max_time) {
                    this_test.status = "timeout";
                }
                GIGO.finish_test(id);
            }
        },
        error: function() {
            var delta;
            if (img_pending) {
                img_pending = 0;
                delta = GIGO.getms() - this_test.start_time;
                if (GIGO.isdef(this_test.time_ms)) {
                    if (delta < this_test.time_ms) {
                        this_test.time_ms = delta;
                    }
                } else {
                    this_test.time_ms = delta;
                }
                this_test.image = 1;
                this_test.status = this_test.time_ms < GIGO.slow ? "bad" : "timeout";
                GIGO.finish_test(id);
            }
        }
    });
    setTimeout(function() {
        var delta;
        if (img_pending) {
            img_pending = 0;
            jQuery(img).attr("src", "/images/knob_red.png");
            delta = GIGO.getms() - this_test.start_time;
            if (GIGO.isdef(this_test.time_ms)) {
                if (delta < this_test.time_ms) {
                    this_test.time_ms = delta;
                }
            } else {
                this_test.time_ms = delta;
            }
            this_test.image = 1;
            this_test.status = this_test.time_ms < GIGO.slow ? "bad" : "timeout";
            GIGO.finish_test(id);
        }
    }, GIGO.max_time);
    jQuery(img).attr("src", url);
    GIGO.update_url(id);
    GIGO.show_debug();
};

GIGO.retest = function() {
    window.location.reload();
};

GIGO.next_in_queue = function() {
    var fname, a;
    if (GIGO.queue.length > 0) {
        a = GIGO.queue.shift();
        GIGO.dequeued.push(a.slice(0));
        try {
            fname = a.shift();
        } catch (e) {
            alert("ERROR: GIGO.next_in_queue: not an array; value=" + a);
        }
        GIGO[fname].apply(GIGO, a);
        if (!GIGO.use_queue) {
            setTimeout(GIGO.next_in_queue, GIGO.slowcount_delay);
        }
    }
    GIGO.update_progress(GIGO);
};

GIGO.start_tests = function() {
    GIGO.browser_tweaks(GIGO);
    GIGO.next_in_queue();
};

GIGO.restart_tests = function() {
    var i, l;
    l = GIGO.dequeued.length;
    for (i = 0; i < l; i = i + 1) {
        GIGO.queue.push(GIGO.dequeued[i]);
    }
    GIGO.update_progress(GIGO);
    GIGO.start_tests();
};

GIGO.setup_tests = function() {
    GIGO.queue.push([ "test_type_json_only", GIGO.options.url.test_asn4, "test_asn4" ]);
    GIGO.queue.push([ "test_type_json_only", GIGO.options.url.test_asn6, "test_asn6" ]);
    GIGO.queue.push([ "test_type_json", GIGO.options.url.test_a, "test_a" ]);
    GIGO.queue.push([ "test_type_json", GIGO.options.url.test_aaaa, "test_aaaa" ]);
    GIGO.queue.push([ "test_type_json", GIGO.options.url.test_ds, "test_ds" ]);
    GIGO.queue.push([ "test_type_json", GIGO.options.url.test_ipv4, "test_ipv4" ]);
    GIGO.queue.push([ "test_type_json", GIGO.options.url.test_ipv6, "test_ipv6" ]);
    GIGO.queue.push([ "test_type_json", GIGO.options.url.test_v6mtu, "test_v6mtu" ]);
    GIGO.queue.push([ "test_type_json", GIGO.options.url.test_v6ns, "test_v6ns" ]);
    GIGO.queue.push([ "test_type_json", GIGO.options.url.test_dsmtu, "test_dsmtu" ]);
    GIGO.show_debug();
    GIGO.prepare_fake();
};

GIGO.fill = function(size, str) {
    var s = "";
    while (s.length < size) {
        s = s + str;
    }
    s = s.substring(0, size);
    return s;
};

GIGO.set_default_options = function(options) {
    options.url = options.hasOwnProperty("url") ? options.url : {};
    options.domain = GIGO.mirrorconfig("site", "name", null);
    options.subdomain = GIGO.mirrorconfig("load", "domain", options.domain);
    options.ipv4 = GIGO.mirrorconfig("load", "ipv4", null);
    options.ipv6 = GIGO.mirrorconfig("load", "ipv6", null);
    options.uri = GIGO.mirrorconfig("options", "ip", "/ip/") + "?callback=?";
    options.img_uri = "/images-nc/bg.gif";
    options.img_uri_big = "/images-nc/knob_valid_green.png?&fill=" + GIGO.fill(1600, "x");
    options.img_bad_uri = "/images-nc/knob_cancel.png";
    options.v6mtu = GIGO.mirrorconfig("options", "v6mtu", "ipv6." + options.subdomain);
    options.url.test_a = "http://ipv4." + options.subdomain + options.uri;
    options.url.test_aaaa = "http://ipv6." + options.subdomain + options.uri;
    options.url.test_ds = "http://ds." + options.subdomain + options.uri;
    options.url.test_ipv4 = "http://" + options.ipv4 + options.uri;
    options.url.test_ipv6 = "http://[" + options.ipv6 + "]:80" + options.uri;
    options.url.test_v6ns = "http://ds.v6ns." + options.subdomain + options.uri;
    options.url.test_v6mtu = "http://" + options.v6mtu + options.uri + "&size=1600&fill=" + GIGO.fill(1600, "x");
    options.url.test_dsmtu = "http://ds." + options.subdomain + options.uri + "&size=1600&fill=" + GIGO.fill(1600, "x");
    options.url.test_buggydns1 = "http://buggydns1." + options.subdomain + options.uri;
    options.url.test_asn4 = "http://ipv4." + options.subdomain + options.uri + "&asn=1";
    options.url.test_asn6 = "http://ipv6." + options.subdomain + options.uri + "&asn=1";
    options.url.test_a_img = "http://ipv4." + options.subdomain + options.img_uri;
    options.url.test_aaaa_img = "http://ipv6." + options.subdomain + options.img_uri;
    options.url.test_ds_img = "http://ds." + options.subdomain + options.img_uri;
    options.url.test_ipv4_img = "http://" + options.ipv4 + options.img_uri;
    options.url.test_ipv6_img = "http://[" + options.ipv6 + "]:80" + options.img_uri;
    options.url.test_v6ns_img = "http://ds.v6ns." + options.subdomain + options.img_uri;
    options.url.test_v6mtu_img = "http://" + options.v6mtu + options.img_uri_big;
    options.url.test_dsmtu_img = "http://ds." + options.subdomain + options.img_uri_big;
    options.url.test_buggydns1_img = "http://buggydns1." + options.subdomain + options.img_uri;
};

GIGO.fix_comment_form_and_tab = function() {
    if (MirrorConfig.options.comment) {
        jQuery("#tabbutton_mail_link").show();
        var url = MirrorConfig.options.comment;
        if (MirrorConfig.options.userdata) {
            if (GIGO.results.ipv4.ip) {
                url = "http://ipv4." + MirrorConfig.options.userdata + "/comment.php";
            } else if (GIGO.results.ipv6.ip) {
                url = "http://ipv6." + MirrorConfig.options.userdata + "/comment.php";
            } else {
                url = "http://ds." + MirrorConfig.options.userdata + "/comment.php";
            }
        }
        $("#commentform").get(0).setAttribute("action", url);
    } else {
        jQuery("#tabbutton_mail_link").hide();
        jQuery("a.tabbutton_mail").hide();
    }
};

GIGO.test_ipv6_gui = function(options) {
    if (!GIGO.isdef(options)) {
        options = {};
    }
    GIGO.options = options;
    GIGO.set_default_options(options);
    jQuery(document).ready(function() {
        jQuery("[name=nobots]").val("serious");
        if (GIGO.is_replay()) {
            jQuery("#replay").show();
        }
        GIGO.start_helpdesk();
        GIGO.setup_tests();
        GIGO.start_tests();
        GIGO.pulse_on();
    });
};

GIGO.redirect = function(page) {
    var newurl, oldpath, newpath;
    newurl = document.location.protocol;
    newurl = newurl + "://";
    newurl = newurl + document.location.hostname;
    if (document.location.port !== 80) {
        newurl = newurl + ":" + document.location.port;
    }
    oldpath = String(document.location.pathname);
    newpath = oldpath.replace(/[^\/]+$/, "");
    newpath = newpath + page;
    newpath = newpath.replace(/\/+/g, "/");
    document.location = newpath;
};
//# sourceMappingURL=index.js.en_US.orig.map