PageSourceSearch

https://test-ipv6.com/index.js.gz.en_US?version=1.1.1033

js test-ipv6.com collected 2026-09-24 08:29:26 UTC 343,396 bytes, 7,557 lines download raw bytes

1// start of index.js
2
3
4
5var GIGO = {}; // We will use this as a name space.
6GIGO.lang = "en";
7GIGO.langUC = "EN";
8GIGO.locale = "en_US";
9
10/*!
11 * Copyright 2010 Jason Fesler.  All rights reserved.
12 * Author: Jason Fesler <[email protected]>
13 * Code deployed at:  http:/test-ipv6.com
14 * Source: http://code.google.com/p/falling-sky/
15 *
16 * The following were also used:
17 *
18 * http://geekswithblogs.net/svanvliet/archive/2006/03/23/simple-javascript-object-dump-function.aspx - Scott Van Vliet
19 * http://jquery.com/ - John Resig
20 * http://sizzlejs.com/ - The Dojo Foundation
21 * http://code.google.com/p/jquery-jsonp/ - Julian Aubourg
22 * http://t.wits.sg (progress bar) - Gary Teo
23 * http://mootools.net -  The MooTools production team
24 *
25 * Full credit is in the source, see
26 * http://code.google.com/p/falling-sky/source/browse/trunk/source/js/ext/NOTICE?r=HEAD
27 *
28 * Most of what you see below will be heavily compressed, including obfuscation
29 * to reduce the served content size.  Use the source tree instead to browse
30 * the source.
31 *
32 * Alternately, view http://beta.test-ipv6.com/index.js,
33 * and scroll down.
34 */
35
36/*! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */
37(function(){function N(p,r){function q(a){if(q[a]!==w)return q[a];var c;if("bug-string-char-index"==a)c="a"!="a"[0];else if("json"==a)c=q("json-stringify")&&q("json-parse");else{var e;if("json-stringify"==a){c=r.stringify;var b="function"==typeof c&&s;if(b){(e=function(){return 1}).toJSON=e;try{b="0"===c(0)&&"0"===c(new t)&&'""'==c(new A)&&c(u)===w&&c(w)===w&&c()===w&&"1"===c(e)&&"[1]"==c([e])&&"[null]"==c([w])&&"null"==c(null)&&"[null,null,null]"==c([w,u,null])&&'{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}'==
38c({a:[e,!0,!1,null,"\x00\b\n\f\r\t"]})&&"1"===c(null,e)&&"[\n 1,\n 2\n]"==c([1,2],null,1)&&'"-271821-04-20T00:00:00.000Z"'==c(new C(-864E13))&&'"+275760-09-13T00:00:00.000Z"'==c(new C(864E13))&&'"-000001-01-01T00:00:00.000Z"'==c(new C(-621987552E5))&&'"1969-12-31T23:59:59.999Z"'==c(new C(-1))}catch(f){b=!1}}c=b}if("json-parse"==a){c=r.parse;if("function"==typeof c)try{if(0===c("0")&&!c(!1)){e=c('{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}');var n=5==e.a.length&&1===e.a[0];if(n){try{n=!c('"\t"')}catch(d){}if(n)try{n=
391!==c("01")}catch(g){}if(n)try{n=1!==c("1.")}catch(m){}}}}catch(X){n=!1}c=n}}return q[a]=!!c}p||(p=k.Object());r||(r=k.Object());var t=p.Number||k.Number,A=p.String||k.String,H=p.Object||k.Object,C=p.Date||k.Date,G=p.SyntaxError||k.SyntaxError,K=p.TypeError||k.TypeError,L=p.Math||k.Math,I=p.JSON||k.JSON;"object"==typeof I&&I&&(r.stringify=I.stringify,r.parse=I.parse);var H=H.prototype,u=H.toString,v,B,w,s=new C(-0xc782b5b800cec);try{s=-109252==s.getUTCFullYear()&&0===s.getUTCMonth()&&1===s.getUTCDate()&&
4010==s.getUTCHours()&&37==s.getUTCMinutes()&&6==s.getUTCSeconds()&&708==s.getUTCMilliseconds()}catch(Q){}if(!q("json")){var D=q("bug-string-char-index");if(!s)var x=L.floor,M=[0,31,59,90,120,151,181,212,243,273,304,334],E=function(a,c){return M[c]+365*(a-1970)+x((a-1969+(c=+(1<c)))/4)-x((a-1901+c)/100)+x((a-1601+c)/400)};(v=H.hasOwnProperty)||(v=function(a){var c={},e;(c.__proto__=null,c.__proto__={toString:1},c).toString!=u?v=function(a){var c=this.__proto__;a=a in(this.__proto__=null,this);this.__proto__=
41c;return a}:(e=c.constructor,v=function(a){var c=(this.constructor||e).prototype;return a in this&&!(a in c&&this[a]===c[a])});c=null;return v.call(this,a)});B=function(a,c){var e=0,b,f,n;(b=function(){this.valueOf=0}).prototype.valueOf=0;f=new b;for(n in f)v.call(f,n)&&e++;b=f=null;e?B=2==e?function(a,c){var e={},b="[object Function]"==u.call(a),f;for(f in a)b&&"prototype"==f||v.call(e,f)||!(e[f]=1)||!v.call(a,f)||c(f)}:function(a,c){var e="[object Function]"==u.call(a),b,f;for(b in a)e&&"prototype"==
42b||!v.call(a,b)||(f="constructor"===b)||c(b);(f||v.call(a,b="constructor"))&&c(b)}:(f="valueOf toString toLocaleString propertyIsEnumerable isPrototypeOf hasOwnProperty constructor".split(" "),B=function(a,c){var e="[object Function]"==u.call(a),b,h=!e&&"function"!=typeof a.constructor&&F[typeof a.hasOwnProperty]&&a.hasOwnProperty||v;for(b in a)e&&"prototype"==b||!h.call(a,b)||c(b);for(e=f.length;b=f[--e];h.call(a,b)&&c(b));});return B(a,c)};
42if(!q("json-stringify")){var U={92:"\\\\",34:'\\"',8:"\\b",
4312:"\\f",10:"\\n",13:"\\r",9:"\\t"},y=function(a,c){return("000000"+(c||0)).slice(-a)},R=function(a){for(var c='"',b=0,h=a.length,f=!D||10<h,n=f&&(D?a.split(""):a);b<h;b++){var d=a.charCodeAt(b);switch(d){case 8:case 9:case 10:case 12:case 13:case 34:case 92:c+=U[d];break;default:if(32>d){c+="\\u00"+y(2,d.toString(16));break}c+=f?n[b]:a.charAt(b)}}return c+'"'},O=function(a,c,b,h,f,n,d){var g,m,k,l,p,r,s,t,q;try{g=c[a]}catch(z){}if("object"==typeof g&&g)if(m=u.call(g),"[object Date]"!=m||v.call(g,
44"toJSON"))"function"==typeof g.toJSON&&("[object Number]"!=m&&"[object String]"!=m&&"[object Array]"!=m||v.call(g,"toJSON"))&&(g=g.toJSON(a));else if(g>-1/0&&g<1/0){if(E){l=x(g/864E5);for(m=x(l/365.2425)+1970-1;E(m+1,0)<=l;m++);for(k=x((l-E(m,0))/30.42);E(m,k+1)<=l;k++);l=1+l-E(m,k);p=(g%864E5+864E5)%864E5;r=x(p/36E5)%24;s=x(p/6E4)%60;t=x(p/1E3)%60;p%=1E3}else m=g.getUTCFullYear(),k=g.getUTCMonth(),l=g.getUTCDate(),r=g.getUTCHours(),s=g.getUTCMinutes(),t=g.getUTCSeconds(),p=g.getUTCMilliseconds();
45g=(0>=m||1E4<=m?(0>m?"-":"+")+y(6,0>m?-m:m):y(4,m))+"-"+y(2,k+1)+"-"+y(2,l)+"T"+y(2,r)+":"+y(2,s)+":"+y(2,t)+"."+y(3,p)+"Z"}else g=null;b&&(g=b.call(c,a,g));if(null===g)return"null";m=u.call(g);if("[object Boolean]"==m)return""+g;if("[object Number]"==m)return g>-1/0&&g<1/0?""+g:"null";if("[object String]"==m)return R(""+g);if("object"==typeof g){for(a=d.length;a--;)if(d[a]===g)throw K();d.push(g);q=[];c=n;n+=f;if("[object Array]"==m){k=0;for(a=g.length;k<a;k++)m=O(k,g,b,h,f,n,d),q.push(m===w?"null":
46m);a=q.length?f?"[\n"+n+q.join(",\n"+n)+"\n"+c+"]":"["+q.join(",")+"]":"[]"}else B(h||g,function(a){var c=O(a,g,b,h,f,n,d);c!==w&&q.push(R(a)+":"+(f?" ":"")+c)}),a=q.length?f?"{\n"+n+q.join(",\n"+n)+"\n"+c+"}":"{"+q.join(",")+"}":"{}";d.pop();return a}};r.stringify=function(a,c,b){var h,f,n,d;if(F[typeof c]&&c)if("[object Function]"==(d=u.call(c)))f=c;else if("[object Array]"==d){n={};for(var g=0,k=c.length,l;g<k;l=c[g++],(d=u.call(l),"[object String]"==d||"[object Number]"==d)&&(n[l]=1));}if(b)if("[object Number]"==
47(d=u.call(b))){if(0<(b-=b%1))for(h="",10<b&&(b=10);h.length<b;h+=" ");}else"[object String]"==d&&(h=10>=b.length?b:b.slice(0,10));return O("",(l={},l[""]=a,l),f,n,h,"",[])}}if(!q("json-parse")){var V=A.fromCharCode,W={92:"\\",34:'"',47:"/",98:"\b",116:"\t",110:"\n",102:"\f",114:"\r"},b,J,l=function(){b=J=null;throw G();},z=function(){for(var a=J,c=a.length,e,h,f,k,d;b<c;)switch(d=a.charCodeAt(b),d){case 9:case 10:case 13:case 32:b++;break;case 123:case 125:case 91:case 93:case 58:case 44:return e=
48D?a.charAt(b):a[b],b++,e;case 34:e="@";for(b++;b<c;)if(d=a.charCodeAt(b),32>d)l();else if(92==d)switch(d=a.charCodeAt(++b),d){case 92:case 34:case 47:case 98:case 116:case 110:case 102:case 114:e+=W[d];b++;break;case 117:h=++b;for(f=b+4;b<f;b++)d=a.charCodeAt(b),48<=d&&57>=d||97<=d&&102>=d||65<=d&&70>=d||l();e+=V("0x"+a.slice(h,b));break;default:l()}else{if(34==d)break;d=a.charCodeAt(b);for(h=b;32<=d&&92!=d&&34!=d;)d=a.charCodeAt(++b);e+=a.slice(h,b)}if(34==a.charCodeAt(b))return b++,e;l();default:h=
49b;45==d&&(k=!0,d=a.charCodeAt(++b));if(48<=d&&57>=d){for(48==d&&(d=a.charCodeAt(b+1),48<=d&&57>=d)&&l();b<c&&(d=a.charCodeAt(b),48<=d&&57>=d);b++);if(46==a.charCodeAt(b)){for(f=++b;f<c&&(d=a.charCodeAt(f),48<=d&&57>=d);f++);f==b&&l();b=f}d=a.charCodeAt(b);if(101==d||69==d){d=a.charCodeAt(++b);43!=d&&45!=d||b++;for(f=b;f<c&&(d=a.charCodeAt(f),48<=d&&57>=d);f++);f==b&&l();b=f}return+a.slice(h,b)}k&&l();if("true"==a.slice(b,b+4))return b+=4,!0;if("false"==a.slice(b,b+5))return b+=5,!1;if("null"==a.slice(b,
50b+4))return b+=4,null;l()}return"$"},P=function(a){var c,b;"$"==a&&l();if("string"==typeof a){if("@"==(D?a.charAt(0):a[0]))return a.slice(1);if("["==a){for(c=[];;b||(b=!0)){a=z();if("]"==a)break;b&&(","==a?(a=z(),"]"==a&&l()):l());","==a&&l();c.push(P(a))}return c}if("{"==a){for(c={};;b||(b=!0)){a=z();if("}"==a)break;b&&(","==a?(a=z(),"}"==a&&l()):l());","!=a&&"string"==typeof a&&"@"==(D?a.charAt(0):a[0])&&":"==z()||l();c[a.slice(1)]=P(z())}return c}l()}return a},T=function(a,b,e){e=S(a,b,e);e===
51w?delete a[b]:a[b]=e},S=function(a,b,e){var h=a[b],f;if("object"==typeof h&&h)if("[object Array]"==u.call(h))for(f=h.length;f--;)T(h,f,e);else B(h,function(a){T(h,a,e)});return e.call(a,b,h)};r.parse=function(a,c){var e,h;b=0;J=""+a;e=P(z());"$"!=z()&&l();b=J=null;return c&&"[object Function]"==u.call(c)?S((h={},h[""]=e,h),"",c):e}}}r.runInContext=N;return r}var K=typeof define==="function"&&define.amd,F={"function":!0,object:!0},G=F[typeof exports]&&exports&&!exports.nodeType&&exports,k=F[typeof window]&&
52window||this,t=G&&F[typeof module]&&module&&!module.nodeType&&"object"==typeof global&&global;
52!t||t.global!==t&&t.window!==t&&t.self!==t||(k=t);if(G&&!K)N(k,G);else{var L=k.JSON,Q=k.JSON3,M=!1,A=N(k,k.JSON3={noConflict:function(){M||(M=!0,k.JSON=L,k.JSON3=Q,L=Q=null);return A}});k.JSON={parse:A.parse,stringify:A.stringify}}K&&define(function(){return A})}).call(this);
53
54/*! jQuery v1.12.2 | (c) jQuery Foundation | jquery.org/license */
55!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.2
vendor: 17,072 bytes, line 55
55",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+N+")*)|.*)\\)|)",P=new RegExp(L+"+","g"),Q=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),R=new RegExp("^"+L+"*,"+L+"*"),S=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),T=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),U=new RegExp(O),V=new RegExp("^"+M+"$"),W={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M+"|[*])"),ATTR:new RegExp("^"+N),PSEUDO:new RegExp("^"+O),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},X=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Z=/^[^{]+\{\s*\[native \w/,$=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,_=/[+~]/,aa=/'|\\/g,ba=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),ca=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},da=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(ea){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fa(a,b,d,e){var f,h,j,k,l,o,r,s,w=b&&b.ownerDocument,x=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==x&&9!==x&&11!==x)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==x&&(o=$.exec(a)))if(f=o[1]){if(9===x){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(w&&(j=w.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(o[2])return H.apply(d,b.getElementsByTagName(a)),d;if((f=o[3])&&c.getElementsByClassName&&b.getElementsByClassName)return H.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==x)w=b,s=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(aa,"\\$&"):b.setAttribute("id",k=u),r=g(a),h=r.length,l=V.test(k)?"#"+k:"[id='"+k+"']";while(h--)r[h]=l+" "+qa(r[h]);s=r.join(","),w=_.test(a)&&oa(b.parentNode)||b}if(s)try{return H.apply(d,w.querySelectorAll(s)),d}catch(y){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(Q,"$1"),b,d,e)}function ga(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ha(a){return a[u]=!0,a}function ia(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ja(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function ka(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function la(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function na(a){return ha(function(b){return b=+b,ha(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function oa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=fa.support={},f=fa.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fa.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ia(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ia(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Z.test(n.getElementsByClassName),c.getById=ia(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}},d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(ba,ca);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return"undefined"!=typeof b.getElementsByClassName&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=Z.test(n.querySelectorAll))&&(ia(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ia(function(a){var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Z.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ia(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",O)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Z.test(o.compareDocumentPosition),t=b||Z.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return ka(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?ka(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},fa.matches=function(a,b){return fa(a,null,null,b)},fa.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(T,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fa(b,n,null,[a]).length>0},fa.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fa.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fa.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fa.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fa.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fa.selectors={cacheLength:50,createPseudo:ha,match:W,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(ba,ca),a[3]=(a[3]||a[4]||a[5]||"").replace(ba,ca),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fa.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fa.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return W.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&U.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(ba,ca).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fa.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(P," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fa.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ha(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ha(function(a){var b=[],c=[],d=h(a.replace(Q,"$1"));return d[u]?ha(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ha(function(a){return function(b){return fa(a,b).length>0}}),contains:ha(function(a){return a=a.replace(ba,ca),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ha(function(a){return V.test(a||"")||fa.error("unsupported lang: "+a),a=a.replace(ba,ca).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Y.test(a.nodeName)}
vendor: 10,751 bytes, line 55
55,input:function(a){return X.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:na(function(){return[0]}),last:na(function(a,b){return[b-1]}),eq:na(function(a,b,c){return[0>c?c+b:c]}),even:na(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:na(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:na(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:na(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=la(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=ma(b);function pa(){}pa.prototype=d.filters=d.pseudos,d.setFilters=new pa,g=fa.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=R.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=S.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(Q," ")}),h=h.slice(c.length));for(g in d.filter)!(e=W[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fa.error(a):z(a,i).slice(0)};function qa(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function ra(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j,k=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(j=b[u]||(b[u]={}),i=j[b.uniqueID]||(j[b.uniqueID]={}),(h=i[d])&&h[0]===w&&h[1]===f)return k[2]=h[2];if(i[d]=k,k[2]=a(b,c,g))return!0}}}function sa(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ta(a,b,c){for(var d=0,e=b.length;e>d;d++)fa(a,b[d],c);return c}function ua(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function va(a,b,c,d,e,f){return d&&!d[u]&&(d=va(d)),e&&!e[u]&&(e=va(e,f)),ha(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ta(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ua(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ua(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ua(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function wa(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ra(function(a){return a===b},h,!0),l=ra(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[ra(sa(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return va(i>1&&sa(m),i>1&&qa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(Q,"$1"),c,e>i&&wa(a.slice(i,e)),f>e&&wa(a=a.slice(e)),f>e&&qa(a))}m.push(c)}return sa(m)}function xa(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=F.call(i));u=ua(u)}H.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&fa.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ha(f):f}return h=fa.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wa(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xa(e,d)),f.selector=a}return f},i=fa.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(ba,ca),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=W.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(ba,ca),_.test(j[0].type)&&oa(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qa(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,!b||_.test(a)&&oa(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ia(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ia(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ja("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ia(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ja("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ia(function(a){return null==a.getAttribute("disabled")})||ja(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fa}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.uniqueSort=n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},v=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},w=n.expr.match.needsContext,x=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,y=/^.[^:#\[\.,]*$/;function z(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(y.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return n.inArray(a,b)>-1!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;e>b;b++)if(n.contains(d[b],this))return!0}));for(b=0;e>b;b++)n.find(a,d[b],c);return c=this.pushStack(e>1?n.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(z(this,a||[],!1))},not:function(a){return this.pushStack(z(this,a||[],!0))},is:function(a){return!!z(this,"string"==typeof a&&w.test(a)?n(a):a||[],!1).length}});var A,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=n.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||A,"string"==typeof a){if(e="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:B.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),x.test(e[1])&&n.isPlainObject(b))for(e in b)n.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}if(f=d.getElementById(e[2]),f&&f.parentNode){if(f.id!==e[2])return A.find(a);this.length=1,this[0]=f}return this.context=d,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof c.ready?c.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};C.prototype=n.fn,A=n(d);var D=/^(?:parents|prev(?:Until|All))/,E={children:!0,contents:!0,next:!0,prev:!0};n.fn.extend({has:function(a){var b,c=n(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(n.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=w.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?n.inArray(this[0],n(a)):n.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.uniqueSort(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function F(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return u(a,"parentNode")},parentsUntil:function(a,b,c){return u(a,"parentNode",c)},next:function(a){return F(a,"nextSibling")},prev:function(a){return F(a,"previousSibling")},nextAll:function(a){return u(a,"nextSibling")},prevAll:function(a){return u(a,"previousSibling")},nextUntil:function(a,b,c){return u(a,"nextSibling",c)},prevUntil:function(a,b,c){return u(a,"previousSibling",c)},siblings:function(a){return v((a.parentNode||{}).firstChild,a)},children:function(a){return v(a.firstChild)},contents:function(a){return n.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(E[a]||(e=n.uniqueSort(e)),D.test(a)&&(e=e.reverse())),this.pushStack(e)}});var G=/\S+/g;function H(a){var b={};return n.each(a.match(G)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?H(a):n.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){n.each(b,function(b,c){n.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==n.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return n.each(arguments,function(a,b){var c;while((c=n.inArray(b,f,c))>-1)f.splice(c,1),h>=c&&h--}),this},has:function(a){return a?n.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=!0,c||j.disable(),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.pu
vendor: 4,130 bytes, lines 55-56
55sh(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().progress(c.notify).done(c.resolve).fail(c.reject):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=e.call(arguments),d=c.length,f=1!==d||a&&n.isFunction(a.promise)?d:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(d){b[a]=this,c[a]=arguments.length>1?e.call(arguments):d,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(d>1)for(i=new Array(d),j=new Array(d),k=new Array(d);d>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().progress(h(b,j,i)).done(h(b,k,c)).fail(g.reject):--f;return f||g.resolveWith(k,c),g.promise()}});var I;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(I.resolveWith(d,[n]),n.fn.triggerHandler&&(n(d).triggerHandler("ready"),n(d).off("ready"))))}});function J(){d.addEventListener?(d.removeEventListener("DOMContentLoaded",K),a.removeEventListener("load",K)):(d.detachEvent("onreadystatechange",K),a.detachEvent("onload",K))}function K(){(d.addEventListener||"load"===a.event.type||"complete"===d.readyState)&&(J(),n.ready())}n.ready.promise=function(b){if(!I)if(I=n.Deferred(),"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll)a.setTimeout(n.ready);else if(d.addEventListener)d.addEventListener("DOMContentLoaded",K),a.addEventListener("load",K);else{d.attachEvent("onreadystatechange",K),a.attachEvent("onload",K);var c=!1;try{c=null==a.frameElement&&d.documentElement}catch(e){}c&&c.doScroll&&!function f(){if(!n.isReady){try{c.doScroll("left")}catch(b){return a.setTimeout(f,50)}J(),n.ready()}}()}return I.promise(b)},n.ready.promise();var L;for(L in n(l))break;l.ownFirst="0"===L,l.inlineBlockNeedsLayout=!1,n(function(){var a,b,c,e;c=d.getElementsByTagName("body")[0],c&&c.style&&(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",l.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(e))}),function(){var a=d.createElement("div");l.deleteExpando=!0;try{delete a.test}catch(b){l.deleteExpando=!1}a=null}();var M=function(a){var b=n.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b},N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(O,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}n.data(a,b,c)}else c=void 0;
56}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}
vendor: 4,101 bytes, line 56
56:{toJSON:n.noop}),"object"!=typeof b&&"function"!=typeof b||(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=n._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}}),function(){var a;l.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,e;return c=d.getElementsByTagName("body")[0],c&&c.style?(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(d.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(e),a):void 0}}();var T=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,U=new RegExp("^(?:([+-])=|)("+T+")([a-z%]*)$","i"),V=["Top","Right","Bottom","Left"],W=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)};function X(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return n.css(a,b,"")},i=h(),j=c&&c[3]||(n.cssNumber[b]?"":"px"),k=(n.cssNumber[b]||"px"!==j&&+i)&&U.exec(n.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,n.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var Y=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;
vendor: 6,432 bytes, line 56
56for(h in c)Y(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}!function(){var a=d.createElement("div"),b=d.createDocumentFragment(),c=d.createElement("input");a.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",l.leadingWhitespace=3===a.firstChild.nodeType,l.tbody=!a.getElementsByTagName("tbody").length,l.htmlSerialize=!!a.getElementsByTagName("link").length,l.html5Clone="<:nav></:nav>"!==d.createElement("nav").cloneNode(!0).outerHTML,c.type="checkbox",c.checked=!0,b.appendChild(c),l.appendChecked=c.checked,a.innerHTML="<textarea>x</textarea>",l.noCloneChecked=!!a.cloneNode(!0).lastChild.defaultValue,b.appendChild(a),c=d.createElement("input"),c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),a.appendChild(c),l.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,l.noCloneEvent=!!a.addEventListener,a[n.expando]=1,l.attributes=!a.getAttribute(n.expando)}();var da={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:l.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]};da.optgroup=da.option,da.tbody=da.tfoot=da.colgroup=da.caption=da.thead,da.th=da.td;function ea(a,b){var c,d,e=0,f="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||n.nodeName(d,b)?f.push(d):n.merge(f,ea(d,b));return void 0===b||b&&n.nodeName(a,b)?n.merge([a],f):f}function fa(a,b){for(var c,d=0;null!=(c=a[d]);d++)n._data(c,"globalEval",!b||n._data(b[d],"globalEval"))}var ga=/<|&#?\w+;/,ha=/<tbody/i;function ia(a){Z.test(a.type)&&(a.defaultChecked=a.checked)}function ja(a,b,c,d,e){for(var f,g,h,i,j,k,m,o=a.length,p=ca(b),q=[],r=0;o>r;r++)if(g=a[r],g||0===g)if("object"===n.type(g))n.merge(q,g.nodeType?[g]:g);else if(ga.test(g)){i=i||p.appendChild(b.createElement("div")),j=($.exec(g)||["",""])[1].toLowerCase(),m=da[j]||da._default,i.innerHTML=m[1]+n.htmlPrefilter(g)+m[2],f=m[0];while(f--)i=i.lastChild;if(!l.leadingWhitespace&&aa.test(g)&&q.push(b.createTextNode(aa.exec(g)[0])),!l.tbody){g="table"!==j||ha.test(g)?"<table>"!==m[1]||ha.test(g)?0:i:i.firstChild,f=g&&g.childNodes.length;while(f--)n.nodeName(k=g.childNodes[f],"tbody")&&!k.childNodes.length&&g.removeChild(k)}n.merge(q,i.childNodes),i.textContent="";while(i.firstChild)i.removeChild(i.firstChild);i=p.lastChild}else q.push(b.createTextNode(g));i&&p.removeChild(i),l.appendChecked||n.grep(ea(q,"input"),ia),r=0;while(g=q[r++])if(d&&n.inArray(g,d)>-1)e&&e.push(g);else if(h=n.contains(g.ownerDocument,g),i=ea(p.appendChild(g),"script"),h&&fa(i),c){f=0;while(g=i[f++])_.test(g.type||"")&&c.push(g)}return i=null,p}!function(){var b,c,e=d.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(l[b]=c in a)||(e.setAttribute(c,"t"),l[b]=e.attributes[c].expando===!1);e=null}();var ka=/^(?:input|select|textarea)$/i,la=/^key/,ma=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,na=/^(?:focusinfocus|focusoutblur)$/,oa=/^([^.]*)(?:\.(.+)|)/;function pa(){return!0}function qa(){return!1}function ra(){try{return d.activeElement}catch(a){}}function sa(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)sa(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=qa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return n().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=n.guid++)),a.each(function(){n.event.add(this,b,e,d,c)})}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=n.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return"undefined"==typeof n||a&&n.event.triggered===a.type?void 0:n.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(G)||[""],h=b.length;while(h--)f=oa.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=n.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=n.event.special[o]||{},l=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},i),(m=g[o])||(m=g[o]=[],m.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,l):m.push(l),n.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=n.hasData(a)&&n._data(a);if(r&&(k=r.events)){b=(b||"").match(G)||[""],j=b.length;while(j--)if(h=oa.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=m.length;while(f--)g=m[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(m.splice(f,1),g.selector&&m.delegateCount--,l.remove&&l.remove.call(a,g));i&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(k)&&(delete r.handle,n._removeData(a,"events"))}},trigger:function(b,c,e,f){var g,h,i,j,l,m,o,p=[e||d],q=k.call(b,"type")?b.type:b,r=k.call(b,"namespace")?b.namespace.split("."):[];if(i=m=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!na.test(q+n.event.triggered)&&(q.indexOf(".")>
vendor: 9,867 bytes, line 56
56-1&&(r=q.split("."),q=r.shift(),r.sort()),h=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=r.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:n.makeArray(c,[b]),l=n.event.special[q]||{},f||!l.trigger||l.trigger.apply(e,c)!==!1)){if(!f&&!l.noBubble&&!n.isWindow(e)){for(j=l.delegateType||q,na.test(j+q)||(i=i.parentNode);i;i=i.parentNode)p.push(i),m=i;m===(e.ownerDocument||d)&&p.push(m.defaultView||m.parentWindow||a)}o=0;while((i=p[o++])&&!b.isPropagationStopped())b.type=o>1?j:l.bindType||q,g=(n._data(i,"events")||{})[b.type]&&n._data(i,"handle"),g&&g.apply(i,c),g=h&&i[h],g&&g.apply&&M(i)&&(b.result=g.apply(i,c),b.result===!1&&b.preventDefault());if(b.type=q,!f&&!b.isDefaultPrevented()&&(!l._default||l._default.apply(p.pop(),c)===!1)&&M(e)&&h&&e[q]&&!n.isWindow(e)){m=e[h],m&&(e[h]=null),n.event.triggered=q;try{e[q]()}catch(s){}n.event.triggered=void 0,m&&(e[h]=m)}return b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,d,f,g,h=[],i=e.call(arguments),j=(n._data(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())a.rnamespace&&!a.rnamespace.test(g.namespace)||(a.handleObj=g,a.data=g.data,d=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==d&&(a.result=d)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&("click"!==a.type||isNaN(a.button)||a.button<1))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>-1:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},fix:function(a){if(a[n.expando])return a;var b,c,e,f=a.type,g=a,h=this.fixHooks[f];h||(this.fixHooks[f]=h=ma.test(f)?this.mouseHooks:la.test(f)?this.keyHooks:{}),e=h.props?this.props.concat(h.props):this.props,a=new n.Event(g),b=e.length;while(b--)c=e[b],a[c]=g[c];return a.target||(a.target=g.srcElement||d),3===a.target.nodeType&&(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,h.filter?h.filter(a,g):a},props:"altKey bubbles cancelable ctrlKey currentTarget detail eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,e,f,g=b.button,h=b.fromElement;return null==a.pageX&&null!=b.clientX&&(e=a.target.ownerDocument||d,f=e.documentElement,c=e.body,a.pageX=b.clientX+(f&&f.scrollLeft||c&&c.scrollLeft||0)-(f&&f.clientLeft||c&&c.clientLeft||0),a.pageY=b.clientY+(f&&f.scrollTop||c&&c.scrollTop||0)-(f&&f.clientTop||c&&c.clientTop||0)),!a.relatedTarget&&h&&(a.relatedTarget=h===a.target?b.toElement:h),a.which||void 0===g||(a.which=1&g?1:2&g?3:4&g?2:0),a}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==ra()&&this.focus)try{return this.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function(){return this===ra()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return n.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c){var d=n.extend(new n.Event,c,{type:a,isSimulated:!0});n.event.trigger(d,null,b),d.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=d.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)}:function(a,b,c){var d="on"+b;a.detachEvent&&("undefined"==typeof a[d]&&(a[d]=null),a.detachEvent(d,c))},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?pa:qa):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={constructor:n.Event,isDefaultPrevented:qa,isPropagationStopped:qa,isImmediatePropagationStopped:qa,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=pa,a&&(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=pa,a&&!this.isSimulated&&(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=pa,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||n.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),l.submit||(n.event.special.submit={setup:function(){return n.nodeName(this,"form")?!1:void n.event.add(this,"click._submit keypress._submit",function(a){var b=a.target,c=n.nodeName(b,"input")||n.nodeName(b,"button")?n.prop(b,"form"):void 0;c&&!n._data(c,"submit")&&(n.event.add(c,"submit._submit",function(a){a._submitBubble=!0}),n._data(c,"submit",!0))})},postDispatch:function(a){a._submitBubble&&(delete a._submitBubble,this.parentNode&&!a.isTrigger&&n.event.simulate("submit",this.parentNode,a))},teardown:function(){return n.nodeName(this,"form")?!1:void n.event.remove(this,"._submit")}}),l.change||(n.event.special.change={setup:function(){return ka.test(this.nodeName)?("checkbox"!==this.type&&"radio"!==this.type||(n.event.add(this,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName&&(this._justChanged=!0)}),n.event.add(this,"click._change",function(a){this._justChanged&&!a.isTrigger&&(this._justChanged=!1),n.event.simulate("change",this,a)})),!1):void n.event.add(this,"beforeactivate._change",function(a){var b=a.target;ka.test(b.nodeName)&&!n._data(b,"change")&&(n.event.add(b,"change._change",function(a){!this.parentNode||a.isSimulated||a.isTrigger||n.event.simulate("change",this.parentNode,a)}),n._data(b,"change",!0))})},handle:function(a){var b=a.target;return this!==b||a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj.handler.apply(this,arguments):void 0},teardown:function(){return n.event.remove(this,"._change"),!ka.test(this.nodeName)}}),l.focusin||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a))};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=n._data(d,b);e||d.addEventListener(a,c,!0),n._data(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=n._data(d,b)-1;e?n._data(d,b,e):(d.removeEventListener(a,c,!0),n._removeData(d,b))}}}),n.fn.extend({on:function(a,b,c,d){return sa(this,a,b,c,d)},one:function(a,b,c,d){return sa(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=qa),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ta=/ jQuery\d+="(?:null|\d+)"/g,ua=new RegExp("<(?:"+ba+")[\\s/>]","i"),va=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,wa=/<script|<style|<link/i,xa=/checked\s*(?:[^=]|=\s*.checked.)/i,ya=/^true\/(.*)/,za=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,Aa=ca(d),Ba=Aa.appendChild(d.createElement("div"));function Ca(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function Da(a){return a.type=(null!==n.find.attr(a,"type"))+"/"+a.type,a}function Ea(a){var b=ya.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Fa(a,b){if(1===b.nodeType&&n.hasData(a)){var c,d,e,f=n._data(a),g=n._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)n.event.add(b,c,h[c][d])}g.data&&(g.data=n.extend({},g.data))}}function Ga(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!l.noCloneEvent&&b[n.expando]){e=n._data(b);for(d in e.events)n.removeEvent(b,d,e.handle);b.removeAttribute(n.expando)}"script"===c&&b.text!==a.text?(Da(b).text=a.text,Ea(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),l.html5Clone&&a.innerHTML&&!n.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&Z.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}}function Ha(a,b,c,d){b=f.apply([],b);var e,g,h,i,j,k,m=0,o=a.length,p=o-1,q=b[0],r=n.isFunction(q);
vendor: 14,454 bytes, lines 56-57
56if(r||o>1&&"string"==typeof q&&!l.checkClone&&xa.test(q))return a.each(function(e){var f=a.eq(e);r&&(b[0]=q.call(this,e,f.html())),Ha(f,b,c,d)});if(o&&(k=ja(b,a[0].ownerDocument,!1,a,d),e=k.firstChild,1===k.childNodes.length&&(k=e),e||d)){for(i=n.map(ea(k,"script"),Da),h=i.length;o>m;m++)g=k,m!==p&&(g=n.clone(g,!0,!0),h&&n.merge(i,ea(g,"script"))),c.call(a[m],g,m);if(h)for(j=i[i.length-1].ownerDocument,n.map(i,Ea),m=0;h>m;m++)g=i[m],_.test(g.type||"")&&!n._data(g,"globalEval")&&n.contains(j,g)&&(g.src?n._evalUrl&&n._evalUrl(g.src):n.globalEval((g.text||g.textContent||g.innerHTML||"").replace(za,"")));k=e=null}return a}function Ia(a,b,c){for(var d,e=b?n.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||n.cleanData(ea(d)),d.parentNode&&(c&&n.contains(d.ownerDocument,d)&&fa(ea(d,"script")),d.parentNode.removeChild(d));return a}n.extend({htmlPrefilter:function(a){return a.replace(va,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h,i=n.contains(a.ownerDocument,a);if(l.html5Clone||n.isXMLDoc(a)||!ua.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(Ba.innerHTML=a.outerHTML,Ba.removeChild(f=Ba.firstChild)),!(l.noCloneEvent&&l.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(d=ea(f),h=ea(a),g=0;null!=(e=h[g]);++g)d[g]&&Ga(e,d[g]);if(b)if(c)for(h=h||ea(a),d=d||ea(f),g=0;null!=(e=h[g]);g++)Fa(e,d[g]);else Fa(a,f);return d=ea(f,"script"),d.length>0&&fa(d,!i&&ea(a,"script")),d=h=e=null,f},cleanData:function(a,b){for(var d,e,f,g,h=0,i=n.expando,j=n.cache,k=l.attributes,m=n.event.special;null!=(d=a[h]);h++)if((b||M(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)m[e]?n.event.remove(d,e):n.removeEvent(d,e,g.handle);j[f]&&(delete j[f],k||"undefined"==typeof d.removeAttribute?d[i]=void 0:d.removeAttribute(i),c.push(f))}}}),n.fn.extend({domManip:Ha,detach:function(a){return Ia(this,a,!0)},remove:function(a){return Ia(this,a)},text:function(a){return Y(this,function(a){return void 0===a?n.text(this):this.empty().append((this[0]&&this[0].ownerDocument||d).createTextNode(a))},null,a,arguments.length)},append:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.appendChild(a)}})},prepend:function(){return Ha(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ca(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ha(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&n.cleanData(ea(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&n.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return Y(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(ta,""):void 0;if("string"==typeof a&&!wa.test(a)&&(l.htmlSerialize||!ua.test(a))&&(l.leadingWhitespace||!aa.test(a))&&!da[($.exec(a)||["",""])[1].toLowerCase()]){a=n.htmlPrefilter(a);try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ea(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ha(this,arguments,function(b){var c=this.parentNode;n.inArray(this,a)<0&&(n.cleanData(ea(this)),c&&c.replaceChild(b,this))},a)}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=0,e=[],f=n(a),h=f.length-1;h>=d;d++)c=d===h?this:this.clone(!0),n(f[d])[b](c),g.apply(e,c.get());return this.pushStack(e)}});var Ja,Ka={HTML:"block",BODY:"block"};function La(a,b){var c=n(b.createElement(a)).appendTo(b.body),d=n.css(c[0],"display");return c.detach(),d}function Ma(a){var b=d,c=Ka[a];return c||(c=La(a,b),"none"!==c&&c||(Ja=(Ja||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=(Ja[0].contentWindow||Ja[0].contentDocument).document,b.write(),b.close(),c=La(a,b),Ja.detach()),Ka[a]=c),c}var Na=/^margin/,Oa=new RegExp("^("+T+")(?!px)[a-z%]+$","i"),Pa=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e},Qa=d.documentElement;!function(){var b,c,e,f,g,h,i=d.createElement("div"),j=d.createElement("div");if(j.style){j.style.cssText="float:left;opacity:.5",l.opacity="0.5"===j.style.opacity,l.cssFloat=!!j.style.cssFloat,j.style.backgroundClip="content-box",j.cloneNode(!0).style.backgroundClip="",l.clearCloneStyle="content-box"===j.style.backgroundClip,i=d.createElement("div"),i.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",j.innerHTML="",i.appendChild(j),l.boxSizing=""===j.style.boxSizing||""===j.style.MozBoxSizing||""===j.style.WebkitBoxSizing,n.extend(l,{reliableHiddenOffsets:function(){return null==b&&k(),f},boxSizingReliable:function(){return null==b&&k(),e},pixelMarginRight:function(){return null==b&&k(),c},pixelPosition:function(){return null==b&&k(),b},reliableMarginRight:function(){return null==b&&k(),g},reliableMarginLeft:function(){return null==b&&k(),h}});function k(){var k,l,m=d.documentElement;m.appendChild(i),j.style.cssText="-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",b=e=h=!1,c=g=!0,a.getComputedStyle&&(l=a.getComputedStyle(j),b="1%"!==(l||{}).top,h="2px"===(l||{}).marginLeft,e="4px"===(l||{width:"4px"}).width,j.style.marginRight="50%",c="4px"===(l||{marginRight:"4px"}).marginRight,k=j.appendChild(d.createElement("div")),k.style.cssText=j.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",k.style.marginRight=k.style.width="0",j.style.width="1px",g=!parseFloat((a.getComputedStyle(k)||{}).marginRight),j.removeChild(k)),j.style.display="none",f=0===j.getClientRects().length,f&&(j.style.display="",j.innerHTML="<table><tr><td></td><td>t</td></tr></table>",k=j.getElementsByTagName("td"),k[0].style.cssText="margin:0;border:0;padding:0;display:none",f=0===k[0].offsetHeight,f&&(k[0].style.display="",k[1].style.display="none",f=0===k[0].offsetHeight)),m.removeChild(i)}}}();var Ra,Sa,Ta=/^(top|right|bottom|left)$/;a.getComputedStyle?(Ra=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)},Sa=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ra(a),g=c?c.getPropertyValue(b)||c[b]:void 0,""!==g&&void 0!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),c&&!l.pixelMarginRight()&&Oa.test(g)&&Na.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f),void 0===g?g:g+""}):Qa.currentStyle&&(Ra=function(a){return a.currentStyle},Sa=function(a,b,c){var d,e,f,g,h=a.style;return c=c||Ra(a),g=c?c[b]:void 0,null==g&&h&&h[b]&&(g=h[b]),Oa.test(g)&&!Ta.test(b)&&(d=h.left,e=a.runtimeStyle,f=e&&e.left,f&&(e.left=a.currentStyle.left),h.left="fontSize"===b?"1em":g,g=h.pixelLeft+"px",h.left=d,f&&(e.left=f)),void 0===g?g:g+""||"auto"});function Ua(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Va=/alpha\([^)]*\)/i,Wa=/opacity\s*=\s*([^)]*)/i,Xa=/^(none|table(?!-c[ea]).+)/,Ya=new RegExp("^("+T+")(.*)$","i"),Za={position:"absolute",visibility:"hidden",display:"block"},$a={letterSpacing:"0",fontWeight:"400"},_a=["Webkit","O","Moz","ms"],ab=d.createElement("div").style;function bb(a){if(a in ab)return a;var b=a.charAt(0).toUpperCase()+a.slice(1),c=_a.length;while(c--)if(a=_a[c]+b,a in ab)return a}function cb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=n._data(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&W(d)&&(f[g]=n._data(d,"olddisplay",Ma(d.nodeName)))):(e=W(d),(c&&"none"!==c||!e)&&n._data(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}function db(a,b,c){var d=Ya.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function eb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+V[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+V[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+V[f]+"Width",!0,e))):(g+=n.css(a,"padding"+V[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+V[f]+"Width",!0,e)));return g}function fb(b,c,e){var f=!0,g="width"===c?b.offsetWidth:b.offsetHeight,h=Ra(b),i=l.boxSizing&&"border-box"===n.css(b,"boxSizing",!1,h);if(d.msFullscreenElement&&a.top!==a&&b.getClientRects().length&&(g=Math.round(100*b.getBoundingClientRect()[c])),0>=g||null==g){if(g=Sa(b,c,h),(0>g||null==g)&&(g=b.style[c]),Oa.test(g))return g;f=i&&(l.boxSizingReliable()||g===b.style[c]),g=parseFloat(g)||0}return g+eb(b,c,e||(i?"border":"content"),f,h)+"px"}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Sa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":l.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;if(b=n.cssProps[h]||(n.cssProps[h]=bb(h)||h),g=n.cssHooks[b]||n.cssHooks[h],void 0===c)return g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b];if(f=typeof c,"string"===f&&(e=U.exec(c))&&e[1]&&(c=X(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(n.cssNumber[h]?"":"px")),l.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),!(g&&"set"in g&&void 0===(c=g.set(a,c,d)))))try{i[b]=c}catch(j){}}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=bb(h)||h),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(f=g.get(a,!0,c)),void 0===f&&(f=Sa(a,b,d)),"normal"===f&&b in $a&&(f=$a[b]),""===c||c?(e=parseFloat(f),c===!0||isFinite(e)?e||0:f):f}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?Xa.test(n.css(a,"display"))&&0===a.offsetWidth?Pa(a,Za,function(){return fb(a,b,d)}):fb(a,b,d):void 0},set:function(a,c,d){var e=d&&Ra(a);return db(a,c,d?eb(a,b,d,l.boxSizing&&"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),l.opacity||(n.cssHooks.opacity={get:function(a,b){return Wa.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=n.isNumeric(b)?"alpha(opacity="+100*b+")":"",f=d&&d.filter||c.filter||"";c.zoom=1,(b>=1||""===b)&&""===n.trim(f.replace(Va,""))&&c.removeAttribute&&(c.removeAttribute("filter"),""===b||d&&!d.filter)||(c.filter=Va.test(f)?f.replace(Va,e):f+" "+e)}}),n.cssHooks.marginRight=Ua(l.reliableMarginRight,function(a,b){return b?Pa(a,{display:"inline-block"},Sa,[a,"marginRight"]):void 0}),n.cssHooks.marginLeft=Ua(l.reliableMarginLeft,function(a,b){
57return b?(parseFloat(Sa(a,"marginLeft"))||(n.contains(a.ownerDocument,a)?a.getBoundingClientRect().left-Pa(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}):0))+"px":void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+V[d]+b]=f[d]||f[d-2]||f[0];return e}},Na.test(a)||(n.cssHooks[a+b].set=db)}),n.fn.extend({css:function(a,b){return Y(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Ra(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return cb(this,!0)},hide:function(){return cb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){W(this)?n(this).show():n(this).hide()})}});function gb(a,b,c,d,e){return new gb.prototype.init(a,b,c,d,e)}n.Tween=gb,gb.prototype={constructor:gb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||n.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=gb.propHooks[this.prop];return a&&a.get?a.get(this):gb.propHooks._default.get(this)},run:function(a){var b,c=gb.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):gb.propHooks._default.set(this),this}},gb.prototype.init.prototype=gb.prototype,gb.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[n.cssProps[a.prop]]&&!n.cssHooks[a.prop]?a.elem[a.prop]=a.now:n.style(a.elem,a.prop,a.now+a.unit)}}},gb.propHooks.scrollTop=gb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},n.fx=gb.prototype.init,n.fx.step={};var hb,ib,jb=/^(?:toggle|show|hide)$/,kb=/queueHooks$/;function lb(){return a.setTimeout(function(){hb=void 0}),hb=n.now()}function mb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=V[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function nb(a,b,c){for(var d,e=(qb.tweeners[b]||[]).concat(qb.tweeners["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ob(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&W(a),r=n._data(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,"display"),k="none"===j?
vendor: 21,191 bytes, line 57
57n._data(a,"olddisplay")||Ma(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(l.inlineBlockNeedsLayout&&"inline"!==Ma(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],jb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(o))"inline"===("none"===j?Ma(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=n._data(a,"fxshow",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,"fxshow");for(b in o)n.style(a,b,o[b])});for(d in o)g=nb(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function pb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function qb(a,b,c){var d,e,f=0,g=qb.prefilters.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=hb||lb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{},easing:n.easing._default},c),originalProperties:b,originalOptions:c,startTime:hb||lb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(pb(k,j.opts.specialEasing);g>f;f++)if(d=qb.prefilters[f].call(j,a,k,j.opts))return n.isFunction(d.stop)&&(n._queueHooks(j.elem,j.opts.queue).stop=n.proxy(d.stop,d)),d;return n.map(k,nb,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(qb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return X(c.elem,a,U.exec(b),c),c}]},tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.match(G);for(var c,d=0,e=a.length;e>d;d++)c=a[d],qb.tweeners[c]=qb.tweeners[c]||[],qb.tweeners[c].unshift(b)},prefilters:[ob],prefilter:function(a,b){b?qb.prefilters.unshift(a):qb.prefilters.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(W).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=qb(this,n.extend({},a),f);(e||n._data(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=n._data(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&kb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=n._data(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(mb(b,!0),a,d,e)}}),n.each({slideDown:mb("show"),slideUp:mb("hide"),slideToggle:mb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=n.timers,c=0;for(hb=n.now();c<b.length;c++)a=b[c],a()||b[c]!==a||b.splice(c--,1);b.length||n.fx.stop(),hb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){ib||(ib=a.setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){a.clearInterval(ib),ib=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(b,c){return b=n.fx?n.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a,b=d.createElement("input"),c=d.createElement("div"),e=d.createElement("select"),f=e.appendChild(d.createElement("option"));c=d.createElement("div"),c.setAttribute("className","t"),c.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",a=c.getElementsByTagName("a")[0],b.setAttribute("type","checkbox"),c.appendChild(b),a=c.getElementsByTagName("a")[0],a.style.cssText="top:1px",l.getSetAttribute="t"!==c.className,l.style=/top/.test(a.getAttribute("style")),l.hrefNormalized="/a"===a.getAttribute("href"),l.checkOn=!!b.value,l.optSelected=f.selected,l.enctype=!!d.createElement("form").enctype,e.disabled=!0,l.optDisabled=!f.disabled,b=d.createElement("input"),b.setAttribute("value",""),l.input=""===b.getAttribute("value"),b.value="t",b.setAttribute("type","radio"),l.radioValue="t"===b.value}();var rb=/\r/g,sb=/[\x20\t\r\n\f]+/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a)).replace(sb," ")}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],(c.selected||i===e)&&(l.optDisabled?!c.disabled:null===c.getAttribute("disabled"))&&(!c.parentNode.disabled||!n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)if(d=e[g],n.inArray(n.valHooks.option.get(d),f)>-1)try{d.selected=c=!0}catch(h){d.scrollHeight}else d.selected=!1;return c||(a.selectedIndex=-1),e}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>-1:void 0}},l.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var tb,ub,vb=n.expr.attrHandle,wb=/^(?:checked|selected)$/i,xb=l.getSetAttribute,yb=l.input;n.fn.extend({attr:function(a,b){return Y(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),e=n.attrHooks[b]||(n.expr.match.bool.test(b)?ub:tb)),void 0!==c?null===c?void n.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=n.find.attr(a,b),null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!l.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(G);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)?yb&&xb||!wb.test(c)?a[d]=!1:a[n.camelCase("default-"+c)]=a[d]=!1:n.attr(a,c,""),a.removeAttribute(xb?c:d)}}),ub={set:function(a,b,c){return b===!1?n.removeAttr(a,c):yb&&xb||!wb.test(c)?a.setAttribute(!xb&&n.propFix[c]||c,c):a[n.camelCase("default-"+c)]=a[c]=!0,c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=vb[b]||n.find.attr;yb&&xb||!wb.test(b)?vb[b]=function(a,b,d){var e,f;return d||(f=vb[b],vb[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,vb[b]=f),e}:vb[b]=function(a,b,c){return c?void 0:a[n.camelCase("default-"+b)]?b.toLowerCase():null}}),yb&&xb||(n.attrHooks.value={set:function(a,b,c){return n.nodeName(a,"input")?void(a.defaultValue=b):tb&&tb.set(a,b,c)}}),xb||(tb={set:function(a,b,c){var d=a.getAttributeNode(c);return d||a.setAttributeNode(d=a.ownerDocument.createAttribute(c)),d.value=b+="","value"===c||b===a.getAttribute(c)?b:void 0}},vb.id=vb.name=vb.coords=function(a,b,c){var d;return c?void 0:(d=a.getAttributeNode(b))&&""!==d.value?d.value:null},n.valHooks.button={get:function(a,b){var c=a.getAttributeNode(b);return c&&c.specified?c.value:void 0},set:tb.set},n.attrHooks.contenteditable={set:function(a,b,c){tb.set(a,""===b?!1:b,c)}},n.each(["width","height"],function(a,b){n.attrHooks[b]={set:function(a,c){return""===c?(a.setAttribute(b,"auto"),c):void 0}}})),l.style||(n.attrHooks.style={get:function(a){return a.style.cssText||void 0},set:function(a,b){return a.style.cssText=b+""}});var zb=/^(?:input|select|textarea|button|object)$/i,Ab=/^(?:a|area)$/i;n.fn.extend({prop:function(a,b){return Y(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return a=n.propFix[a]||a,this.each(function(){try{this[a]=void 0,delete this[a]}catch(b){}})}}),n.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&n.isXMLDoc(a)||(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=n.find.attr(a,"tabindex");return b?parseInt(b,10):zb.test(a.nodeName)||Ab.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),l.hrefNormalized||n.each(["href","src"],function(a,b){n.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}),l.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex),null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this}),l.enctype||(n.propFix.enctype="encoding");var Bb=/[\t\r\n\f]/g;function Cb(a){return n.attr(a,"class")||""}n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,Cb(this)))});if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=Cb(c),d=1===c.nodeType&&(" "+e+" ").replace(Bb," ")){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=n.trim(d),e!==h&&n.attr(c,"class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,Cb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(G)||[];while(c=this[i++])if(e=Cb(c),d=1===c.nodeType&&(" "+e+" ").replace(Bb," ")){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=n.trim(d),e!==h&&n.attr(c,"class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):n.isFunction(a)?this.each(function(c){n(this).toggleClass(a.call(this,c,Cb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=n(this),f=a.match(G)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=Cb(this),b&&n._data(this,"__className__",b),n.attr(this,"class",b||a===!1?"":n._data(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+Cb(c)+" ").replace(Bb," ").indexOf(b)>-1)return!0;return!1}}),n.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(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var Db=a.location,Eb=n.now(),Fb=/\?/,Gb=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;n.parseJSON=function(b){if(a.JSON&&a.JSON.parse)return a.JSON.parse(b+"");var c,d=null,e=n.trim(b+"");return e&&!n.trim(e.replace(Gb,function(a,b,e,f){return c&&b&&(d=0),0===d?a:(c=e||b,d+=!f-!e,"")}))?Function("return "+e)():n.error("Invalid JSON: "+b)},n.parseXML=function(b){var c,d;if(!b||"string"!=typeof b)return null;try{a.DOMParser?(d=new a.DOMParser,c=d.parseFromString(b,"text/xml")):(c=new a.ActiveXObject("Microsoft.XMLDOM"),c.async="false",c.loadXML(b))}catch(e){c=void 0}return c&&c.documentElement&&!c.getElementsByTagName("parsererror").length||n.error("Invalid XML: "+b),c};var Hb=/#.*$/,Ib=/([?&])_=[^&]*/,Jb=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Kb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Lb=/^(?:GET|HEAD)$/,Mb=/^\/\//,Nb=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Ob={},Pb={},Qb="*/".concat("*"),Rb=Db.href,Sb=Nb.exec(Rb.toLowerCase())||[];function Tb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(G)||[];if(n.isFunction(c))while(d=f[e++])"+"===d.charAt(0)?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Ub(a,b,c,d){var e={},f=a===Pb;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Vb(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(d in b)void 0!==b[d]&&((e[d]?a:c||(c={}))[d]=b[d]);return c&&n.extend(!0,a,c),a}function Wb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===e&&(e=a.mimeType||b.getResponseHeader("Content-Type"));if(e)for(g in h)if(h[g]&&h[g].test(e)){i.unshift(g);break}if(i[0]in c)f=i[0];else{for(g in c){if(!i[0]||a.converters[g+" "+i[0]]){f=g;break}d||(d=g)}f=f||d}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function Xb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Rb,type:"GET",isLocal:Kb.test(Sb[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Qb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Vb(Vb(a,n.ajaxSettings),b):Vb(n.ajaxSettings,a)},ajaxPrefilter:Tb(Ob),ajaxTransport:Tb(Pb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var d,e,f,g,h,i,j,k,l=n.ajaxSetup({},c),m=l.context||l,o=l.context&&(m.nodeType||m.jquery)?n(m):n.event,p=n.Deferred(),q=n.Callbacks("once memory"),r=l.statusCode||{},s={},t={},u=0,v="canceled",w={readyState:0,getResponseHeader:function(a){var b;if(2===u){if(!k){k={};while(b=Jb.exec(g))k[b[1].toLowerCase()]=b[2]}b=k[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===u?g:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return u||(a=t[c]=t[c]||a,s[a]=b),this},overrideMimeType:function(a){return u||(l.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>u)for(b in a)r[b]=[r[b],a[b]];else w.always(a[w.status]);return this},abort:function(a){var b=a||v;return j&&j.abort(b),y(0,b),this}};if(p.promise(w).complete=q.add,w.success=w.done,w.error=w.fail,l.url=((b||l.url||Rb)+"").replace(Hb,"").replace(Mb,Sb[1]+"//"),l.type=c.method||c.type||l.method||l.type,l.dataTypes=n.trim(l.dataType||"*").toLowerCase().match(G)||[""],null==l.crossDomain&&(d=Nb.exec(l.url.toLowerCase()),l.crossDomain=!(!d||d[1]===Sb[1]&&d[2]===Sb[2]&&(d[3]||("http:"===d[1]?"80":"443"))===(Sb[3]||("http:"===Sb[1]?"80":"443")))),l.data&&l.processData&&"string"!=typeof l.data&&(l.data=n.param(l.data,l.traditional)),Ub(Ob,l,c,w),2===u)return w;i=n.event&&l.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),l.type=l.type.toUpperCase(),l.hasContent=!Lb.test(l.type),f=l.url,l.hasContent||(l.data&&(f=l.url+=(Fb.test(f)?"&":"?")+l.data,delete l.data),l.cache===!1&&(l.url=Ib.test(f)?f.replace(Ib,"$1_="+Eb++):f+(Fb.test(f)?"&":"?")+"_="+Eb++)),l.ifModified&&(n.lastModified[f]&&w.setRequestHeader("If-Modified-Since",n.lastModified[f]),n.etag[f]&&w.setRequestHeader("If-None-Match",n.etag[f])),(l.data&&l.hasContent&&l.contentType!==!1||c.contentType)&&w.setRequestHeader("Content-Type",l.contentType),w.setRequestHeader("Accept",l.dataTypes[0]&&l.accepts[l.dataTypes[0]]?l.accepts[l.dataTypes[0]]+("*"!==l.dataTypes[0]?", "+Qb+"; q=0.01":""):l.accepts["*"]);for(e in l.headers)w.setRequestHeader(e,l.headers[e]);if(l.beforeSend&&(l.beforeSend.call(m,w,l)===!1||2===u))return w.abort();v="abort";for(e in{success:1,error:1,complete:1})w[e](l[e]);if(j=Ub(Pb,l,c,w)){if(w.readyState=1,i&&o.trigger("ajaxSend",[w,l]),2===u)return w;l.async&&l.timeout>0&&(h=a.setTimeout(function(){w.abort("timeout")},l.timeout));try{u=1,j.send(s,y)}catch(x){if(!(2>u))throw x;y(-1,x)}}else y(-1,"No Transport");function y(b,c,d,e){var k,s,t,v,x,y=c;2!==u&&(u=2,h&&a.clearTimeout(h),j=void 0,g=e||"",w.readyState=b>0?4:0,k=b>=200&&300>b||304===b,d&&(v=Wb(l,w,d)),v=Xb(l,v,w,k),k?(l.ifModified&&(x=w.getResponseHeader("Last-Modified"),x&&(n.lastModified[f]=x),x=w.getResponseHeader("etag"),x&&(n.etag[f]=x)),204===b||"HEAD"===l.type?y="nocontent":304===b?y="notmodified":(y=v.state,s=v.data,t=v.error,k=!t)):(t=y,!b&&y||(y="error",0>b&&(b=0))),w.status=b,w.statusText=(c||y)+"",k?p.resolveWith(m,[s,y,w]):p.rejectWith(m,[w,y,t]),w.statusCode(r),r=void 0,i&&o.trigger(k?"ajaxSuccess":"ajaxError",[w,l,k?s:t]),q.fireWith(m,[w,y]),i&&(o.trigger("ajaxComplete",[w,l]),--n.active||n.event.trigger("ajaxStop")))}return w},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax(n.extend({url:a,type:b,dataType:e,data:c,success:d},n.isPlainObject(a)&&a))}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){if(n.isFunction(a))return this.each(function(b){n(this).wrapAll(a.call(this,b))});if(this[0]){var b=n(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&1===a.firstChild.nodeType)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){return n.isFunction(a)?this.each(function(b){n(this).wrapInner(a.call(this,b))}):this.each(function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}});function Yb(a){return a.style&&a.style.display||n.css(a,"display")}function Zb(a){
vendor: 9,897 bytes, lines 57-105
57while(a&&1===a.nodeType){if("none"===Yb(a)||"hidden"===a.type)return!0;a=a.parentNode}return!1}n.expr.filters.hidden=function(a){return l.reliableHiddenOffsets()?a.offsetWidth<=0&&a.offsetHeight<=0&&!a.getClientRects().length:Zb(a)},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var $b=/%20/g,_b=/\[\]$/,ac=/\r?\n/g,bc=/^(?:submit|button|image|reset|file)$/i,cc=/^(?:input|select|textarea|keygen)/i;function dc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||_b.test(a)?d(a,e):dc(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)dc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)dc(c,a[c],b,e);return d.join("&").replace($b,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&cc.test(this.nodeName)&&!bc.test(a)&&(this.checked||!Z.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(ac,"\r\n")}}):{name:b.name,value:c.replace(ac,"\r\n")}}).get()}}),n.ajaxSettings.xhr=void 0!==a.ActiveXObject?function(){return this.isLocal?ic():d.documentMode>8?hc():/^(get|post|head|put|delete|options)$/i.test(this.type)&&hc()||ic()}:hc;var ec=0,fc={},gc=n.ajaxSettings.xhr();a.attachEvent&&a.attachEvent("onunload",function(){for(var a in fc)fc[a](void 0,!0)}),l.cors=!!gc&&"withCredentials"in gc,gc=l.ajax=!!gc,gc&&n.ajaxTransport(function(b){if(!b.crossDomain||l.cors){var c;return{send:function(d,e){var f,g=b.xhr(),h=++ec;if(g.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(f in b.xhrFields)g[f]=b.xhrFields[f];b.mimeType&&g.overrideMimeType&&g.overrideMimeType(b.mimeType),b.crossDomain||d["X-Requested-With"]||(d["X-Requested-With"]="XMLHttpRequest");for(f in d)void 0!==d[f]&&g.setRequestHeader(f,d[f]+"");g.send(b.hasContent&&b.data||null),c=function(a,d){var f,i,j;if(c&&(d||4===g.readyState))if(delete fc[h],c=void 0,g.onreadystatechange=n.noop,d)4!==g.readyState&&g.abort();else{j={},f=g.status,"string"==typeof g.responseText&&(j.text=g.responseText);try{i=g.statusText}catch(k){i=""}f||!b.isLocal||b.crossDomain?1223===f&&(f=204):f=j.text?200:404}j&&e(f,i,j,g.getAllResponseHeaders())},b.async?4===g.readyState?a.setTimeout(c):g.onreadystatechange=fc[h]=c:c()},abort:function(){c&&c(void 0,!0)}}}});function hc(){try{return new a.XMLHttpRequest}catch(b){}}function ic(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}n.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c=d.head||n("head")[0]||d.documentElement;return{send:function(e,f){b=d.createElement("script"),b.async=!0,a.scriptCharset&&(b.charset=a.scriptCharset),b.src=a.url,b.onload=b.onreadystatechange=function(a,c){(c||!b.readyState||/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b.parentNode&&b.parentNode.removeChild(b),b=null,c||f(200,"success"))},c.insertBefore(b,c.firstChild)},abort:function(){b&&b.onload(void 0,!0)}}}});var jc=[],kc=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=jc.pop()||n.expando+"_"+Eb++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(kc.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&kc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(kc,"$1"+e):b.jsonp!==!1&&(b.url+=(Fb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?n(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,jc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||d;var e=x.exec(a),f=!c&&[];return e?[b.createElement(e[1])]:(e=ja([a],b,f),f&&f.length&&n(f).remove(),n.merge([],e.childNodes))};var lc=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&lc)return lc.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=n.trim(a.slice(h,a.length)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(g,f||[a.responseText,b,a])})}),this},n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};function mc(a){return n.isWindow(a)?a:9===a.nodeType?a.defaultView||a.parentWindow:!1}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&n.inArray("auto",[f,i])>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,n.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d={top:0,left:0},e=this[0],f=e&&e.ownerDocument;if(f)return b=f.documentElement,n.contains(b,e)?("undefined"!=typeof e.getBoundingClientRect&&(d=e.getBoundingClientRect()),c=mc(f),{top:d.top+(c.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(c.pageXOffset||b.scrollLeft)-(b.clientLeft||0)}):d},position:function(){if(this[0]){var a,b,c={top:0,left:0},d=this[0];return"fixed"===n.css(d,"position")?b=d.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(c=a.offset()),c.top+=n.css(a[0],"borderTopWidth",!0),c.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-c.top-n.css(d,"marginTop",!0),left:b.left-c.left-n.css(d,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Qa})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c=/Y/.test(b);n.fn[a]=function(d){return Y(this,function(a,d,e){var f=mc(a);return void 0===e?f?b in f?f[b]:f.document.documentElement[d]:a[d]:void(f?f.scrollTo(c?n(f).scrollLeft():e,c?e:n(f).scrollTop()):a[d]=e)},a,d,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=Ua(l.pixelPosition,function(a,c){
58return c?(c=Sa(a,b),Oa.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return Y(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var nc=a.jQuery,oc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=oc),b&&a.jQuery===n&&(a.jQuery=nc),n},b||(a.jQuery=a.$=n),n});
59
60/*
61---
62MooTools: the javascript framework
63
64web build:
65 - http://mootools.net/core/21ecee8cf9f9a4471a45ae1bb3f26e12
66
67packager build:
68 - packager build Core/Browser Core/JSON
69
70...
71*/
72
73/*
74---
75
76name: Core
77
78description: The heart of MooTools.
79
80license: MIT-style license.
81
82copyright: Copyright (c) 2006-2012 [Valerio Proietti](http://mad4milk.net/).
83
84authors: The MooTools production team (http://mootools.net/developers/)
85
86inspiration:
87  - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
88  - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
89
90provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
91
92...
93*/
94
95(function(){
96
97this.MooTools = {
98	version: '1.4.5',
99	build: 'ab8ea8824dc3b24b6666867a2c4ed58ebb762cf0'
100};
101
102// typeOf, instanceOf
103
104var typeOf = this.typeOf = function(item){
105	if (item == null) return 'null';
106	if (item.$family != null) return item.$family();
107
108	if (item.nodeName){
109		if (item.nodeType == 1) return 'element';
110		if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
111	} else if (typeof item.length == 'number'){
112		if (item.callee) return 'arguments';
113		if ('item' in item) return 'collection';
114	}
115
116	return typeof item;
117};
118
119var instanceOf = this.instanceOf = function(item, object){
120	if (item == null) return false;
121	var constructor = item.$constructor || item.constructor;
122	while (constructor){
123		if (constructor === object) return true;
124		constructor = constructor.parent;
125	}
126	/*<ltIE8>*/
127	if (!item.hasOwnProperty) return false;
128	/*</ltIE8>*/
129	return item instanceof object;
130};
131
132// Function overloading
133
134var Function = this.Function;
135
136var enumerables = true;
137for (var i in {toString: 1}) enumerables = null;
138if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
139
140Function.prototype.overloadSetter = function(usePlural){
141	var self = this;
142	return function(a, b){
143		if (a == null) return this;
144		if (usePlural || typeof a != 'string'){
145			for (var k in a) self.call(this, k, a[k]);
146			if (enumerables) for (var i = enumerables.length; i--;){
147				k = enumerables[i];
148				if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
149			}
150		} else {
151			self.call(this, a, b);
152		}
153		return this;
154	};
155};
156
157Function.prototype.overloadGetter = function(usePlural){
158	var self = this;
159	return function(a){
160		var args, result;
161		if (typeof a != 'string') args = a;
162		else if (arguments.length > 1) args = arguments;
163		else if (usePlural) args = [a];
164		if (args){
165			result = {};
166			for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
167		} else {
168			result = self.call(this, a);
169		}
170		return result;
171	};
172};
173
174Function.prototype.extend = function(key, value){
175	this[key] = value;
176}.overloadSetter();
177
178Function.prototype.implement = function(key, value){
179	this.prototype[key] = value;
180}.overloadSetter();
181
182// From
183
184var slice = Array.prototype.slice;
185
186Function.from = function(item){
187	return (typeOf(item) == 'function') ? item : function(){
188		return item;
189	};
190};
191
192Array.from = function(item){
193	if (item == null) return [];
194	return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
195};
196
197Number.from = function(item){
198	var number = parseFloat(item);
199	return isFinite(number) ? number : null;
200};
201
202String.from = function(item){
203	return item + '';
204};
205
206// hide, protect
207
208Function.implement({
209
210	hide: function(){
211		this.$hidden = true;
212		return this;
213	},
214
215	protect: function(){
216		this.$protected = true;
217		return this;
218	}
219
220});
221
222// Type
223
224var Type = this.Type = function(name, object){
225	if (name){
226		var lower = name.toLowerCase();
227		var typeCheck = function(item){
228			return (typeOf(item) == lower);
229		};
230
231		Type['is' + name] = typeCheck;
232		if (object != null){
233			object.prototype.$family = (function(){
234				return lower;
235			}).hide();
236			
237		}
238	}
239
240	if (object == null) return null;
241
242	object.extend(this);
243	object.$constructor = Type;
244	object.prototype.$constructor = object;
245
246	return object;
247};
248
249var toString = Object.prototype.toString;
250
251Type.isEnumerable = function(item){
252	return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
253};
254
255var hooks = {};
256
257var hooksOf = function(object){
258	var type = typeOf(object.prototype);
259	return hooks[type] || (hooks[type] = []);
260};
261
262var implement = function(name, method){
263	if (method && method.$hidden) return;
264
265	var hooks = hooksOf(this);
266
267	for (var i = 0; i < hooks.length; i++){
268		var hook = hooks[i];
269		if (typeOf(hook) == 'type') implement.call(hook, name, method);
270		else hook.call(this, name, method);
271	}
272
273	var previous = this.prototype[name];
274	if (previous == null || !previous.$protected) this.prototype[name] = method;
275
276	if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
277		return method.apply(item, slice.call(arguments, 1));
278	});
279};
280
281var extend = function(name, method){
282	if (method && method.$hidden) return;
283	var previous = this[name];
284	if (previous == null || !previous.$protected) this[name] = method;
285};
286
287Type.implement({
288
289	implement: implement.overloadSetter(),
290
291	extend: extend.overloadSetter(),
292
293	alias: function(name, existing){
294		implement.call(this, name, this.prototype[existing]);
295	}.overloadSetter(),
296
297	mirror: function(hook){
298		hooksOf(this).push(hook);
299		return this;
300	}
301
302});
303
304new Type('Type', Type);
305
306// Default Types
307
308var force = function(name, object, methods){
309	var isType = (object != Object),
310		prototype = object.prototype;
311
312	if (isType) object = new Type(name, object);
313
314	for (var i = 0, l = methods.length; i < l; i++){
315		var key = methods[i],
316			generic = object[key],
317			proto = prototype[key];
318
319		if (generic) generic.protect();
320		if (isType && proto) object.implement(key, proto.protect());
321	}
322
323	if (isType){
324		var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
325		object.forEachMethod = function(fn){
326			if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
327				fn.call(prototype, prototype[methods[i]], methods[i]);
328			}
329			for (var key in prototype) fn.call(prototype, prototype[key], key)
330		};
331	}
332
333	return force;
334};
335
336force('String', String, [
337	'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
338	'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
339])('Array', Array, [
340	'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
341	'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
342])('Number', Number, [
343	'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
344])('Function', Function, [
345	'apply', 'call', 'bind'
346])('RegExp', RegExp, [
347	'exec', 'test'
348])('Object', Object, [
349	'create', 'defineProperty', 'defineProperties', 'keys',
350	'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
351	'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
352])('Date', Date, ['now']);
353
354Object.extend = extend.overloadSetter();
355
356Date.extend('now', function(){
357	return +(new Date);
358});
359
360new Type('Boolean', Boolean);
361
362// fixes NaN returning as Number
363
364Number.prototype.$family = function(){
365	return isFinite(this) ? 'number' : 'null';
366}.hide();
367
368// Number.random
369
370Number.extend('random', function(min, max){
371	return Math.floor(Math.random() * (max - min + 1) + min);
372});
373
374// forEach, each
375
376var hasOwnProperty = Object.prototype.hasOwnProperty;
377Object.extend('forEach', function(object, fn, bind){
378	for (var key in object){
379		if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
380	}
381});
382
383Object.each = Object.forEach;
384
385Array.implement({
386
387	forEach: function(fn, bind){
388		for (var i = 0, l = this.length; i < l; i++){
389			if (i in this) fn.call(bind, this[i], i, this);
390		}
391	},
392
393	each: function(fn, bind){
394		Array.forEach(this, fn, bind);
395		return this;
396	}
397
398});
399
400// Array & Object cloning, Object merging and appending
401
402var cloneOf = function(item){
403	switch (typeOf(item)){
404		case 'array': return item.clone();
405		case 'object': return Object.clone(item);
406		default: return item;
407	}
408};
409
410Array.implement('clone', function(){
411	var i = this.length, clone = new Array(i);
412	while (i--) clone[i] = cloneOf(this[i]);
413	return clone;
414});
415
416var mergeOne = function(source, key, current){
417	switch (typeOf(current)){
418		case 'object':
419			if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
420			else source[key] = Object.clone(current);
421		break;
422		case 'array': source[key] = current.clone(); break;
423		default: source[key] = current;
424	}
425	return source;
426};
427
428Object.extend({
429
430	merge: function(source, k, v){
431		if (typeOf(k) == 'string') return mergeOne(source, k, v);
432		for (var i = 1, l = arguments.length; i < l; i++){
433			var object = arguments[i];
434			for (var key in object) mergeOne(source, key, object[key]);
435		}
436		return source;
437	},
438
439	clone: function(object){
440		var clone = {};
441		for (var key in object) clone[key] = cloneOf(object[key]);
442		return clone;
443	},
444
445	append: function(original){
446		for (var i = 1, l = arguments.length; i < l; i++){
447			var extended = arguments[i] || {};
448			for (var key in extended) original[key] = extended[key];
449		}
450		return original;
451	}
452
453});
454
455// Object-less types
456
457['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
458	new Type(name);
459});
460
461// Unique ID
462
463var UID = Date.now();
464
465String.extend('uniqueID', function(){
466	return (UID++).toString(36);
467});
468
469
470
471})();
472
473
474/*
475---
476
477name: Array
478
479description: Contains Array Prototypes like each, contains, and erase.
480
481license: MIT-style license.
482
483requires: Type
484
485provides: Array
486
487...
488*/
489
490Array.implement({
491
492	/*<!ES5>*/
493	every: function(fn, bind){
494		for (var i = 0, l = this.length >>> 0; i < l; i++){
495			if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
496		}
497		return true;
498	},
499
500	filter: function(fn, bind){
501		var results = [];
502		for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){
503			value = this[i];
504			if (fn.call(bind, value, i, this)) results.push(value);
505		}
506		return results;
507	},
508
509	indexOf: function(item, from){
510		var length = this.length >>> 0;
511		for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){
512			if (this[i] === item) return i;
513		}
514		return -1;
515	},
516
517	map: function(fn, bind){
518		var length = this.length >>> 0, results = Array(length);
519		for (var i = 0; i < length; i++){
520			if (i in this) results[i] = fn.call(bind, this[i], i, this);
521		}
522		return results;
523	},
524
525	some: function(fn, bind){
526		for (var i = 0, l = this.length >>> 0; i < l; i++){
527			if ((i in this) && fn.call(bind, this[i], i, this)) return true;
528		}
529		return false;
530	},
531	/*</!ES5>*/
532
533	clean: function(){
534		return this.filter(function(item){
535			return item != null;
536		});
537	},
538
539	invoke: function(methodName){
540		var args = Array.slice(arguments, 1);
541		return this.map(function(item){
542			return item[methodName].apply(item, args);
543		});
544	},
545
546	associate: function(keys){
547		var obj = {}, length = Math.min(this.length, keys.length);
548		for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
549		return obj;
550	},
551
552	link: function(object){
553		var result = {};
554		for (var i = 0, l = this.length; i < l; i++){
555			for (var key in object){
556				if (object[key](this[i])){
557					result[key] = this[i];
558					delete object[key];
559					break;
560				}
561			}
562		}
563		return result;
564	},
565
566	contains: function(item, from){
567		return this.indexOf(item, from) != -1;
568	},
569
570	append: function(array){
571		this.push.apply(this, array);
572		return this;
573	},
574
575	getLast: function(){
576		return (this.length) ? this[this.length - 1] : null;
577	},
578
579	getRandom: function(){
580		return (this.length) ? this[Number.random(0, this.length - 1)] : null;
581	},
582
583	include: function(item){
584		if (!this.contains(item)) this.push(item);
585		return this;
586	},
587
588	combine: function(array){
589		for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
590		return this;
591	},
592
593	erase: function(item){
594		for (var i = this.length; i--;){
595			if (this[i] === item) this.splice(i, 1);
596		}
597		return this;
598	},
599
600	empty: function(){
601		this.length = 0;
602		return this;
603	},
604
605	flatten: function(){
606		var array = [];
607		for (var i = 0, l = this.length; i < l; i++){
608			var type = typeOf(this[i]);
609			if (type == 'null') continue;
610			array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
611		}
612		return array;
613	},
614
615	pick: function(){
616		for (var i = 0, l = this.length; i < l; i++){
617			if (this[i] != null) return this[i];
618		}
619		return null;
620	},
621
622	hexToRgb: function(array){
623		if (this.length != 3) return null;
624		var rgb = this.map(function(value){
625			if (value.length == 1) value += value;
626			return value.toInt(16);
627		});
628		return (array) ? rgb : 'rgb(' + rgb + ')';
629	},
630
631	rgbToHex: function(array){
632		if (this.length < 3) return null;
633		if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
634		var hex = [];
635		for (var i = 0; i < 3; i++){
636			var bit = (this[i] - 0).toString(16);
637			hex.push((bit.length == 1) ? '0' + bit : bit);
638		}
639		return (array) ? hex : '#' + hex.join('');
640	}
641
642});
643
644
645
646
647/*
648---
649
650name: Function
651
652description: Contains Function Prototypes like create, bind, pass, and delay.
653
654license: MIT-style license.
655
656requires: Type
657
658provides: Function
659
660...
661*/
662
663Function.extend({
664
665	attempt: function(){
666		for (var i = 0, l = arguments.length; i < l; i++){
667			try {
668				return arguments[i]();
669			} catch (e){}
670		}
671		return null;
672	}
673
674});
675
676Function.implement({
677
678	attempt: function(args, bind){
679		try {
680			return this.apply(bind, Array.from(args));
681		} catch (e){}
682
683		return null;
684	},
685
686	/*<!ES5-bind>*/
687	bind: function(that){
688		var self = this,
689			args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
690			F = function(){};
691
692		var bound = function(){
693			var context = that, length = arguments.length;
694			if (this instanceof bound){
695				F.prototype = self.prototype;
696				context = new F;
697			}
698			var result = (!args && !length)
699				? self.call(context)
700				: self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
701			return context == that ? result : context;
702		};
703		return bound;
704	},
705	/*</!ES5-bind>*/
706
707	pass: function(args, bind){
708		var self = this;
709		if (args != null) args = Array.from(args);
710		return function(){
711			return self.apply(bind, args || arguments);
712		};
713	},
714
715	delay: function(delay, bind, args){
716		return setTimeout(this.pass((args == null ? [] : args), bind), delay);
717	},
718
719	periodical: function(periodical, bind, args){
720		return setInterval(this.pass((args == null ? [] : args), bind), periodical);
721	}
722
723});
724
725
726
727
728/*
729---
730
731name: Number
732
733description: Contains Number Prototypes like limit, round, times, and ceil.
734
735license: MIT-style license.
736
737requires: Type
738
739provides: Number
740
741...
742*/
743
744Number.implement({
745
746	limit: function(min, max){
747		return Math.min(max, Math.max(min, this));
748	},
749
750	round: function(precision){
751		precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
752		return Math.round(this * precision) / precision;
753	},
754
755	times: function(fn, bind){
756		for (var i = 0; i < this; i++) fn.call(bind, i, this);
757	},
758
759	toFloat: function(){
760		return parseFloat(this);
761	},
762
763	toInt: function(base){
764		return parseInt(this, base || 10);
765	}
766
767});
768
769Number.alias('each', 'times');
770
771(function(math){
772	var methods = {};
773	math.each(function(name){
774		if (!Number[name]) methods[name] = function(){
775			return Math[name].apply(null, [this].concat(Array.from(arguments)));
776		};
777	});
778	Number.implement(methods);
779})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
780
781
782/*
783---
784
785name: String
786
787description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
788
789license: MIT-style license.
790
791requires: Type
792
793provides: String
794
795...
796*/
797
798String.implement({
799
800	test: function(regex, params){
801		return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
802	},
803
804	contains: function(string, separator){
805		return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : String(this).indexOf(string) > -1;
806	},
807
808	trim: function(){
809		return String(this).replace(/^\s+|\s+$/g, '');
810	},
811
812	clean: function(){
813		return String(this).replace(/\s+/g, ' ').trim();
814	},
815
816	camelCase: function(){
817		return String(this).replace(/-\D/g, function(match){
818			return match.charAt(1).toUpperCase();
819		});
820	},
821
822	hyphenate: function(){
823		return String(this).replace(/[A-Z]/g, function(match){
824			return ('-' + match.charAt(0).toLowerCase());
825		});
826	},
827
828	capitalize: function(){
829		return String(this).replace(/\b[a-z]/g, function(match){
830			return match.toUpperCase();
831		});
832	},
833
834	escapeRegExp: function(){
835		return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
836	},
837
838	toInt: function(base){
839		return parseInt(this, base || 10);
840	},
841
842	toFloat: function(){
843		return parseFloat(this);
844	},
845
846	hexToRgb: function(array){
847		var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
848		return (hex) ? hex.slice(1).hexToRgb(array) : null;
849	},
850
851	rgbToHex: function(array){
852		var rgb = String(this).match(/\d{1,3}/g);
853		return (rgb) ? rgb.rgbToHex(array) : null;
854	},
855
856	substitute: function(object, regexp){
857		return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
858			if (match.charAt(0) == '\\') return match.slice(1);
859			return (object[name] != null) ? object[name] : '';
860		});
861	}
862
863});
864
865
866/*
867---
868
869name: Browser
870
871description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash.
872
873license: MIT-style license.
874
875requires: [Array, Function, Number, String]
876
877provides: [Browser, Window, Document]
878
879...
880*/
881
882(function(){
883
884var document = this.document;
885var window = document.window = this;
886
887var ua = navigator.userAgent.toLowerCase(),
888	platform = navigator.platform.toLowerCase(),
889	UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [null, 'unknown', 0],
890	mode = UA[1] == 'ie' && document.documentMode;
891
892var Browser = this.Browser = {
893
894	extend: Function.prototype.extend,
895
896	name: (UA[1] == 'version') ? UA[3] : UA[1],
897
898	version: mode || parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
899
900	Platform: {
901		name: ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0]
902	},
903
904	Features: {
905		xpath: !!(document.evaluate),
906		air: !!(window.runtime),
907		query: !!(document.querySelector),
908		json: !!(window.JSON)
909	},
910
911	Plugins: {}
912
913};
914
915Browser[Browser.name] = true;
916Browser[Browser.name + parseInt(Browser.version, 10)] = true;
917Browser.Platform[Browser.Platform.name] = true;
918
919// Request
920
921Browser.Request = (function(){
922
923	var XMLHTTP = function(){
924		return new XMLHttpRequest();
925	};
926
927	var MSXML2 = function(){
928		return new ActiveXObject('MSXML2.XMLHTTP');
929	};
930
931	var MSXML = function(){
932		return new ActiveXObject('Microsoft.XMLHTTP');
933	};
934
935	return Function.attempt(function(){
936		XMLHTTP();
937		return XMLHTTP;
938	}, function(){
939		MSXML2();
940		return MSXML2;
941	}, function(){
942		MSXML();
943		return MSXML;
944	});
945
946})();
947
948Browser.Features.xhr = !!(Browser.Request);
949
950// Flash detection
951
952var version = (Function.attempt(function(){
953	return navigator.plugins['Shockwave Flash'].description;
954}, function(){
955	return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
956}) || '0 r0').match(/\d+/g);
957
958Browser.Plugins.Flash = {
959	version: Number(version[0] || '0.' + version[1]) || 0,
960	build: Number(version[2]) || 0
961};
962
963// String scripts
964
965Browser.exec = function(text){
966	if (!text) return text;
967	if (window.execScript){
968		window.execScript(text);
969	} else {
970		var script = document.createElement('script');
971		script.setAttribute('type', 'text/javascript');
972		script.text = text;
973		document.head.appendChild(script);
974		document.head.removeChild(script);
975	}
976	return text;
977};
978
979String.implement('stripScripts', function(exec){
980	var scripts = '';
981	var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(all, code){
982		scripts += code + '\n';
983		return '';
984	});
985	if (exec === true) Browser.exec(scripts);
986	else if (typeOf(exec) == 'function') exec(scripts, text);
987	return text;
988});
989
990// Window, Document
991
992Browser.extend({
993	Document: this.Document,
994	Window: this.Window,
995	Element: this.Element,
996	Event: this.Event
997});
998
999this.Window = this.$constructor = new Type('Window', function(){});
1000
1001this.$family = Function.from('window').hide();
1002
1003Window.mirror(function(name, method){
1004	window[name] = method;
1005});
1006
1007this.Document = document.$constructor = new Type('Document', function(){});
1008
1009document.$family = Function.from('document').hide();
1010
1011Document.mirror(function(name, method){
1012	document[name] = method;
1013});
1014
1015document.html = document.documentElement;
1016if (!document.head) document.head = document.getElementsByTagName('head')[0];
1017
1018if (document.execCommand) try {
1019	document.execCommand("BackgroundImageCache", false, true);
1020} catch (e){}
1021
1022/*<ltIE9>*/
1023if (this.attachEvent && !this.addEventListener){
1024	var unloadEvent = function(){
1025		this.detachEvent('onunload', unloadEvent);
1026		document.head = document.html = document.window = null;
1027	};
1028	this.attachEvent('onunload', unloadEvent);
1029}
1030
1031// IE fails on collections and <select>.options (refers to <select>)
1032var arrayFrom = Array.from;
1033try {
1034	arrayFrom(document.html.childNodes);
1035} catch(e){
1036	Array.from = function(item){
1037		if (typeof item != 'string' && Type.isEnumerable(item) && typeOf(item) != 'array'){
1038			var i = item.length, array = new Array(i);
1039			while (i--) array[i] = item[i];
1040			return array;
1041		}
1042		return arrayFrom(item);
1043	};
1044
1045	var prototype = Array.prototype,
1046		slice = prototype.slice;
1047	['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice'].each(function(name){
1048		var method = prototype[name];
1049		Array[name] = function(item){
1050			return method.apply(Array.from(item), slice.call(arguments, 1));
1051		};
1052	});
1053}
1054/*</ltIE9>*/
1055
1056
1057
1058})();
1059
1060
1061/*
1062---
1063
1064name: JSON
1065
1066description: JSON encoder and decoder.
1067
1068license: MIT-style license.
1069
1070SeeAlso: <http://www.json.org/>
1071
1072requires: [Array, String, Number, Function]
1073
1074provides: JSON
1075
1076...
1077*/
1078
1079if (typeof JSON == 'undefined') this.JSON = {};
1080
1081
1082
1083(function(){
1084
1085var special = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'};
1086
1087var escape = function(chr){
1088	return special[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4);
1089};
1090
1091JSON.validate = function(string){
1092	string = string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
1093					replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
1094					replace(/(?:^|:|,)(?:\s*\[)+/g, '');
1095
1096	return (/^[\],:{}\s]*$/).test(string);
1097};
1098
1099JSON.encode = JSON.stringify ? function(obj){
1100	return JSON.stringify(obj);
1101} : function(obj){
1102	if (obj && obj.toJSON) obj = obj.toJSON();
1103
1104	switch (typeOf(obj)){
1105		case 'string':
1106			return '"' + obj.replace(/[\x00-\x1f\\"]/g, escape) + '"';
1107		case 'array':
1108			return '[' + obj.map(JSON.encode).clean() + ']';
1109		case 'object': case 'hash':
1110			var string = [];
1111			Object.each(obj, function(value, key){
1112				var json = JSON.encode(value);
1113				if (json) string.push(JSON.encode(key) + ':' + json);
1114			});
1115			return '{' + string + '}';
1116		case 'number': case 'boolean': return '' + obj;
1117		case 'null': return 'null';
1118	}
1119
1120	return null;
1121};
1122
1123JSON.decode = function(string, secure){
1124	if (!string || typeOf(string) != 'string') return null;
1125
1126	if (secure || JSON.secure){
1127		if (JSON.parse) return JSON.parse(string);
1128		if (!JSON.validate(string)) throw new Error('JSON could not decode the input; security is enabled and the value is not secure.');
1129	}
1130
1131	return eval('(' + string + ')');
1132};
1133
1134})();
1135
1136
1137/*
1138 * 
1139 * TableSorter 2.0 - Client-side table sorting with ease!
1140 * Version 2.0.5b
1141 * @requires jQuery v1.2.3
1142 * 
1143 * Copyright (c) 2007 Christian Bach
1144 * Examples and docs at: http://tablesorter.com
1145 * Dual licensed under the MIT and GPL licenses:
1146 * http://www.opensource.org/licenses/mit-license.php
1147 * http://www.gnu.org/licenses/gpl.html
1148 * 
1149 */
1150/**
1151 * 
1152 * @description Create a sortable table with multi-column sorting capabilitys
1153 * 
1154 * @example $('table').tablesorter();
1155 * @desc Create a simple tablesorter interface.
1156 * 
1157 * @example $('table').tablesorter({ sortList:[[0,0],[1,0]] });
1158 * @desc Create a tablesorter interface and sort on the first and secound column column headers.
1159 * 
1160 * @example $('table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } });
1161 *          
1162 * @desc Create a tablesorter interface and disableing the first and second  column headers.
1163 *      
1164 * 
1165 * @example $('table').tablesorter({ headers: { 0: {sorter:"integer"}, 1: {sorter:"currency"} } });
1166 * 
1167 * @desc Create a tablesorter interface and set a column parser for the first
1168 *       and second column.
1169 * 
1170 * 
1171 * @param Object
1172 *            settings An object literal containing key/value pairs to provide
1173 *            optional settings.
1174 * 
1175 * 
1176 * @option String cssHeader (optional) A string of the class name to be appended
1177 *         to sortable tr elements in the thead of the table. Default value:
1178 *         "header"
1179 * 
1180 * @option String cssAsc (optional) A string of the class name to be appended to
1181 *         sortable tr elements in the thead on a ascending sort. Default value:
1182 *         "headerSortUp"
1183 * 
1184 * @option String cssDesc (optional) A string of the class name to be appended
1185 *         to sortable tr elements in the thead on a descending sort. Default
1186 *         value: "headerSortDown"
1187 * 
1188 * @option String sortInitialOrder (optional) A string of the inital sorting
1189 *         order can be asc or desc. Default value: "asc"
1190 * 
1191 * @option String sortMultisortKey (optional) A string of the multi-column s
1191ort
1192 *         key. Default value: "shiftKey"
1193 * 
1194 * @option String textExtraction (optional) A string of the text-extraction
1195 *         method to use. For complex html structures inside td cell set this
1196 *         option to "complex", on large tables the complex option can be slow.
1197 *         Default value: "simple"
1198 * 
1199 * @option Object headers (optional) An array containing the forces sorting
1200 *         rules. This option let's you specify a default sorting rule. Default
1201 *         value: null
1202 * 
1203 * @option Array sortList (optional) An array containing the forces sorting
1204 *         rules. This option let's you specify a default sorting rule. Default
1205 *         value: null
1206 * 
1207 * @option Array sortForce (optional) An array containing forced sorting rules.
1208 *         This option let's you specify a default sorting rule, which is
1209 *         prepended to user-selected rules. Default value: null
1210 * 
1211 * @option Boolean sortLocaleCompare (optional) Boolean flag indicating whatever
1212 *         to use String.localeCampare method or not. Default set to true.
1213 * 
1214 * 
1215 * @option Array sortAppend (optional) An array containing forced sorting rules.
1216 *         This option let's you specify a default sorting rule, which is
1217 *         appended to user-selected rules. Default value: null
1218 * 
1219 * @option Boolean widthFixed (optional) Boolean flag indicating if tablesorter
1220 *         should apply fixed widths to the table columns. This is usefull when
1221 *         using the pager companion plugin. This options requires the dimension
1222 *         jquery plugin. Default value: false
1223 * 
1224 * @option Boolean cancelSelection (optional) Boolean flag indicating if
1225 *         tablesorter should cancel selection of the table headers text.
1226 *         Default value: true
1227 * 
1228 * @option Boolean debug (optional) Boolean flag indicating if tablesorter
1229 *         should display debuging information usefull for development.
1230 * 
1231 * @type jQuery
1232 * 
1233 * @name tablesorter
1234 * 
1235 * @cat Plugins/Tablesorter
1236 * 
1237 * @author Christian Bach/[email protected]
1238 */
1239
1240(function ($) {
1241    $.extend({
1242        tablesorter: new
1243        function () {
1244
1245            var parsers = [],
1246                widgets = [];
1247
1248            this.defaults = {
1249                cssHeader: "header",
1250                cssAsc: "headerSortUp",
1251                cssDesc: "headerSortDown",
1252                cssChildRow: "expand-child",
1253                sortInitialOrder: "asc",
1254                sortMultiSortKey: "shiftKey",
1255                sortForce: null,
1256                sortAppend: null,
1257                sortLocaleCompare: true,
1258                textExtraction: "simple",
1259                parsers: {}, widgets: [],
1260                widgetZebra: {
1261                    css: ["even", "odd"]
1262                }, headers: {}, widthFixed: false,
1263                cancelSelection: true,
1264                sortList: [],
1265                headerList: [],
1266                dateFormat: "us",
1267                decimal: '/\.|\,/g',
1268                onRenderHeader: null,
1269                selectorHeaders: 'thead th',
1270                debug: false
1271            };
1272
1273            /* debuging utils */
1274
1275            function benchmark(s, d) {
1276                log(s + "," + (new Date().getTime() - d.getTime()) + "ms");
1277            }
1278
1279            this.benchmark = benchmark;
1280
1281            function log(s) {
1282                if (typeof console != "undefined" && typeof console.debug != "undefined") {
1283                    console.log(s);
1284                } else {
1285                    alert(s);
1286                }
1287            }
1288
1289            /* parsers utils */
1290
1291            function buildParserCache(table, $headers) {
1292
1293                if (table.config.debug) {
1294                    var parsersDebug = "";
1295                }
1296
1297                if (table.tBodies.length == 0) return; // In the case of empty tables
1298                var rows = table.tBodies[0].rows;
1299
1300                if (rows[0]) {
1301
1302                    var list = [],
1303                        cells = rows[0].cells,
1304                        l = cells.length;
1305
1306                    for (var i = 0; i < l; i++) {
1307
1308                        var p = false;
1309
1310                        if ($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter)) {
1311
1312                            p = getParserById($($headers[i]).metadata().sorter);
1313
1314                        } else if ((table.config.headers[i] && table.config.headers[i].sorter)) {
1315
1316                            p = getParserById(table.config.headers[i].sorter);
1317                        }
1318                        if (!p) {
1319
1320                            p = detectParserForColumn(table, rows, -1, i);
1321                        }
1322
1323                        if (table.config.debug) {
1324                            parsersDebug += "column:" + i + " parser:" + p.id + "\n";
1325                        }
1326
1327                        list.push(p);
1328                    }
1329                }
1330
1331                if (table.config.debug) {
1332                    log(parsersDebug);
1333                }
1334
1335                return list;
1336            };
1337
1338            function detectParserForColumn(table, rows, rowIndex, cellIndex) {
1339                var l = parsers.length,
1340                    node = false,
1341                    nodeValue = false,
1342                    keepLooking = true;
1343                while (nodeValue == '' && keepLooking) {
1344                    rowIndex++;
1345                    if (rows[rowIndex]) {
1346                        node = getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex);
1347                        nodeValue = trimAndGetNodeText(table.config, node);
1348                        if (table.config.debug) {
1349                            log('Checking if value was empty on row:' + rowIndex);
1350                        }
1351                    } else {
1352                        keepLooking = false;
1353                    }
1354                }
1355                for (var i = 1; i < l; i++) {
1356                    if (parsers[i].is(nodeValue, table, node)) {
1357                        return parsers[i];
1358                    }
1359                }
1360                // 0 is always the generic parser (text)
1361                return parsers[0];
1362            }
1363
1364            function getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex) {
1365                return rows[rowIndex].cells[cellIndex];
1366            }
1367
1368            function trimAndGetNodeText(config, node) {
1369                return $.trim(getElementText(config, node));
1370            }
1371
1372            function getParserById(name) {
1373                var l = parsers.length;
1374                for (var i = 0; i < l; i++) {
1375                    if (parsers[i].id.toLowerCase() == name.toLowerCase()) {
1376                        return parsers[i];
1377                    }
1378                }
1379                return false;
1380            }
1381
1382            /* utils */
1383
1384            function buildCache(table) {
1385
1386                if (table.config.debug) {
1387                    var cacheTime = new Date();
1388                }
1389
1390                var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
1391                    totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0,
1392                    parsers = table.config.parsers,
1393                    cache = {
1394                        row: [],
1395                        normalized: []
1396                    };
1397
1398                for (var i = 0; i < totalRows; ++i) {
1399
1400                    /** Add the table data to main data array */
1401                    var c = $(table.tBodies[0].rows[i]),
1402                        cols = [];
1403
1404                    // if this is a child row, add it to the last row's children and
1405                    // continue to the next row
1406                    if (c.hasClass(table.config.cssChildRow)) {
1407                        cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c);
1408                        // go to the next for loop
1409                        continue;
1410                    }
1411
1412                    cache.row.push(c);
1413
1414                    for (var j = 0; j < totalCells; ++j) {
1415                        cols.push(parsers[j].format(getElementText(table.config, c[0].cells[j]), table, c[0].cells[j]));
1416                    }
1417
1418                    cols.push(cache.normalized.length); // add position for rowCache
1419                    cache.normalized.push(cols);
1420                    cols = null;
1421                };
1422
1423                if (table.config.debug) {
1424                    benchmark("Building cache for " + totalRows + " rows:", cacheTime);
1425                }
1426
1427                return cache;
1428            };
1429
1430            function getElementText(config, node) {
1431
1432                var text = "";
1433
1434                if (!node) return "";
1435
1436                if (!config.supportsTextContent) config.supportsTextContent = node.textContent || false;
1437
1438                if (config.textExtraction == "simple") {
1439                    if (config.supportsTextContent) {
1440                        text = node.textContent;
1441                    } else {
1442                        if (node.childNodes[0] && node.childNodes[0].hasChildNodes()) {
1443                            text = node.childNodes[0].innerHTML;
1444                        } else {
1445                            text = node.innerHTML;
1446                        }
1447                    }
1448                } else {
1449                    if (typeof(config.textExtraction) == "function") {
1450                        text = config.textExtraction(node);
1451                    } else {
1452                        text = $(node).text();
1453                    }
1454                }
1455                return text;
1456            }
1457
1458            function appendToTable(table, cache) {
1459
1460                if (table.config.debug) {
1461                    var appendTime = new Date()
1462                }
1463
1464                var c = cache,
1465                    r = c.row,
1466                    n = c.normalized,
1467                    totalRows = n.length,
1468                    checkCell = (n[0].length - 1),
1469                    tableBody = $(table.tBodies[0]),
1470                    rows = [];
1471
1472
1473                for (var i = 0; i < totalRows; i++) {
1474                    var pos = n[i][checkCell];
1475
1476                    rows.push(r[pos]);
1477
1478                    if (!table.config.appender) {
1479
1480                        //var o = ;
1481                        var l = r[pos].length;
1482                        for (var j = 0; j < l; j++) {
1483                            tableBody[0].appendChild(r[pos][j]);
1484                        }
1485
1486                        // 
1487                    }
1488                }
1489
1490
1491
1492                if (table.config.appender) {
1493
1494                    table.config.appender(table, rows);
1495                }
1496
1497                rows = null;
1498
1499                if (table.config.debug) {
1500                    benchmark("Rebuilt table:", appendTime);
1501                }
1502
1503                // apply table widgets
1504                applyWidget(table);
1505
1506                // trigger sortend
1507                setTimeout(function () {
1508                    $(table).trigger("sortEnd");
1509                }, 0);
1510
1511            };
1512
1513            function buildHeaders(table) {
1514
1515                if (table.config.debug) {
1516                    var time = new Date();
1517                }
1518
1519                var meta = ($.metadata) ? true : false;
1520                
1521                var header_index = computeTableHeaderCellIndexes(table);
1522
1523                $tableHeaders = $(table.config.selectorHeaders, table).each(function (index) {
1524
1525                    this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex];
1526                    // this.column = index;
1527                    this.order = formatSortingOrder(table.config.sortInitialOrder);
1528                    
1529					
1530					this.count = this.order;
1531
1532                    if (checkHeaderMetadata(this) || checkHeaderOptions(table, index)) this.sortDisabled = true;
1533					if (checkHeaderOptionsSortingLocked(table, index)) this.order = this.lockedOrder = checkHeaderOptionsSortingLocked(table, index);
1534
1535                    if (!this.sortDisabled) {
1536                        var $th = $(this).addClass(table.config.cssHeader);
1537                        if (table.config.onRenderHeader) table.config.onRenderHeader.apply($th);
1538                    }
1539
1540                    // add cell to headerList
1541                    table.config.headerList[index] = this;
1542                });
1543
1544                if (table.config.debug) {
1545                    benchmark("Built headers:", time);
1546                    log($tableHeaders);
1547                }
1548
1549                return $tableHeaders;
1550
1551            };
1552
1553            // from:
1554            // http://www.javascripttoolbox.com/lib/table/examples.php
1555            // http://www.javascripttoolbox.com/temp/table_cellindex.html
1556
1557
1558            function computeTableHeaderCellIndexes(t) {
1559                var matrix = [];
1560                var lookup = {};
1561                var thead = t.getElementsByTagName('THEAD')[0];
1562                var trs = thead.getElementsByTagName('TR');
1563
1564                for (var i = 0; i < trs.length; i++) {
1565                    var cells = trs[i].cells;
1566                    for (var j = 0; j < cells.length; j++) {
1567                        var c = cells[j];
1568
1569                        var rowIndex = c.parentNode.rowIndex;
1570                        var cellId = rowIndex + "-" + c.cellIndex;
1571                        var rowSpan = c.rowSpan || 1;
1572                        var colSpan = c.colSpan || 1
1573                        var firstAvailCol;
1574                        if (typeof(matrix[rowIndex]) == "undefined") {
1575                            matrix[rowIndex] = [];
1576                        }
1577                        // Find first available column in the first row
1578                        for (var k = 0; k < matrix[rowIndex].length + 1; k++) {
1579                            if (typeof(matrix[rowIndex][k]) == "undefined") {
1580                                firstAvailCol = k;
1581                                break;
1582                            }
1583                        }
1584                        lookup[cellId] = firstAvailCol;
1585                        for (var k = rowIndex; k < rowIndex + rowSpan; k++) {
1586                            if (typeof(matrix[k]) == "undefined") {
1587                                matrix[k] = [];
1588                            }
1589                            var matrixrow = matrix[k];
1590                            for (var l = firstAvailCol; l < firstAvailCol + colSpan; l++) {
1591                                matrixrow[l] = "x";
1592                            }
1593                        }
1594                    }
1595                }
1596                return lookup;
1597            }
1598
1599            function checkCellColSpan(table, rows, row) {
1600                var arr = [],
1601                    r = table.tHead.rows,
1602                    c = r[row].cells;
1603
1604                for (var i = 0; i < c.length; i++) {
1605                    var cell = c[i];
1606
1607                    if (cell.colSpan > 1) {
1608                        arr = arr.concat(checkCellColSpan(table, headerArr, row++));
1609                    } else {
1610                        if (table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row + 1])) {
1611                            arr.push(cell);
1612                        }
1613                        // headerArr[row] = (i+row);
1614                    }
1615                }
1616                return arr;
1617            };
1618
1619            function checkHeaderMetadata(cell) {
1620                if (($.metadata) && ($(cell).metadata().sorter === false)) {
1621                    return true;
1622                };
1623                return false;
1624            }
1625
1626            function checkHeaderOptions(table, i) {
1627                if ((table.config.headers[i]) && (table.config.headers[i].sorter === false)) {
1628                    return true;
1629                };
1630                return false;
1631            }
1632			
1633			 function checkHeaderOptionsSortingLocked(table, i) {
1634                if ((table.config.headers[i]) && (table.config.headers[i].lockedOrder)) return table.config.headers[i].lockedOrder;
1635                return false;
1636            }
1637			
1638            function applyWidget(table) {
1639                var c = table.config.widgets;
1640                var l = c.length;
1641                for (var i = 0; i < l; i++) {
1642
1643                    getWidgetById(c[i]).format(table);
1644                }
1645
1646            }
1647
1648            function getWidgetById(name) {
1649                var l = widgets.length;
1650                for (var i = 0; i < l; i++) {
1651                    if (widgets[i].id.toLowerCase() == name.toLowerCase()) {
1652                        return widgets[i];
1653                    }
1654                }
1655            };
1656
1657            function formatSortingOrder(v) {
1658                if (typeof(v) != "Number") {
1659                    return (v.toLowerCase() == "desc") ? 1 : 0;
1660                } else {
1661                    return (v == 1) ? 1 : 0;
1662                }
1663            }
1664
1665            function isValueInArray(v, a) {
1666                var l = a.length;
1667                for (var i = 0; i < l; i++) {
1668                    if (a[i][0] == v) {
1669                        return true;
1670                    }
1671                }
1672                return false;
1673            }
1674
1675            function setHeadersCss(table, $headers, list, css) {
1676                // remove all header information
1677                $headers.removeClass(css[0]).removeClass(css[1]);
1678
1679                var h = [];
1680                $headers.each(function (offset) {
1681                    if (!this.sortDisabled) {
1682                        h[this.column] = $(this);
1683                    }
1684                });
1685
1686                var l = list.length;
1687                for (var i = 0; i < l; i++) {
1688                    h[list[i][0]].addClass(css[list[i][1]]);
1689                }
1690            }
1691
1692            function fixColumnWidth(table, $headers) {
1693                var c = table.config;
1694                if (c.widthFixed) {
1695                    var colgroup = $('<colgroup>');
1696                    $("tr:first td", table.tBodies[0]).each(function () {
1697                        colgroup.append($('<col>').css('width', $(this).width()));
1698                    });
1699                    $(table).prepend(colgroup);
1700                };
1701            }
1702
1703            function updateHeaderSortCount(table, sortList) {
1704                var c = table.config,
1705                    l = sortList.length;
1706                for (var i = 0; i < l; i++) {
1707                    var s = sortList[i],
1708                        o = c.headerList[s[0]];
1709                    o.count = s[1];
1710                    o.count++;
1711                }
1712            }
1713
1714            /* sorting methods */
1715
1716            function multisort(table, sortList, cache) {
1717
1718                if (table.config.debug) {
1719                    var sortTime = new Date();
1720                }
1721
1722                var dynamicExp = "var sortWrapper = function(a,b) {",
1723                    l = sortList.length;
1724
1725                // TODO: inline functions.
1726                for (var i = 0; i < l; i++) {
1727
1728                    var c = sortList[i][0];
1729                    var order = sortList[i][1];
1730                    // var s = (getCachedSortType(table.config.parsers,c) == "text") ?
1731                    // ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ?
1732                    // "sortNumeric" : "sortNumericDesc");
1733                    // var s = (table.config.parsers[c].type == "text") ? ((order == 0)
1734                    // ? makeSortText(c) : makeSortTextDesc(c)) : ((order == 0) ?
1735                    // makeSortNumeric(c) : makeSortNumericDesc(c));
1736                    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));
1737                    var e = "e" + i;
1738
1739                    dynamicExp += "var " + e + " = " + s; // + "(a[" + c + "],b[" + c
1740                    // + "]); ";
1741                    dynamicExp += "if(" + e + ") { return " + e + "; } ";
1742                    dynamicExp += "else { ";
1743
1744                }
1745
1746                // if value is the same keep orignal order
1747                var orgOrderCol = cache.normalized[0].length - 1;
1748                dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";
1749
1750                for (var i = 0; i < l; i++) {
1751                    dynamicExp += "}; ";
1752                }
1753
1754                dynamicExp += "return 0; ";
1755                dynamicExp += "}; ";
1756
1757                if (table.config.debug) {
1758                    benchmark("Evaling expression:" + dynamicExp, new Date());
1759                }
1760
1761                eval(dynamicExp);
1762
1763                cache.normalized.sort(sortWrapper);
1764
1765                if (table.config.debug) {
1766                    benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime);
1767                }
1768
1769                return cache;
1770            };
1771
1772            function makeSortFunction(type, direction, index) {
1773                var a = "a[" + index + "]",
1774                    b = "b[" + index + "]";
1775                if (type == 'text' && direction == 'asc') {
1776                    return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + a + " < " + b + ") ? -1 : 1 )));";
1777                } else if (type == 'text' && direction == 'desc') {
1778                    return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + b + " < " + a + ") ? -1 : 1 )));";
1779                } else if (type == 'numeric' && direction == 'asc') {
1780                    return "(" + a + " === null && " + b + " === null) ? 0 :(" 
1780+ a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + a + " - " + b + "));";
1781                } else if (type == 'numeric' && direction == 'desc') {
1782                    return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + b + " - " + a + "));";
1783                }
1784            };
1785
1786            function makeSortText(i) {
1787                return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));";
1788            };
1789
1790            function makeSortTextDesc(i) {
1791                return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));";
1792            };
1793
1794            function makeSortNumeric(i) {
1795                return "a[" + i + "]-b[" + i + "];";
1796            };
1797
1798            function makeSortNumericDesc(i) {
1799                return "b[" + i + "]-a[" + i + "];";
1800            };
1801
1802            function sortText(a, b) {
1803                if (table.config.sortLocaleCompare) return a.localeCompare(b);
1804                return ((a < b) ? -1 : ((a > b) ? 1 : 0));
1805            };
1806
1807            function sortTextDesc(a, b) {
1808                if (table.config.sortLocaleCompare) return b.localeCompare(a);
1809                return ((b < a) ? -1 : ((b > a) ? 1 : 0));
1810            };
1811
1812            function sortNumeric(a, b) {
1813                return a - b;
1814            };
1815
1816            function sortNumericDesc(a, b) {
1817                return b - a;
1818            };
1819
1820            function getCachedSortType(parsers, i) {
1821                return parsers[i].type;
1822            }; /* public methods */
1823            this.construct = function (settings) {
1824                return this.each(function () {
1825                    // if no thead or tbody quit.
1826                    if (!this.tHead || !this.tBodies) return;
1827                    // declare
1828                    var $this, $document, $headers, cache, config, shiftDown = 0,
1829                        sortOrder;
1830                    // new blank config object
1831                    this.config = {};
1832                    // merge and extend.
1833                    config = $.extend(this.config, $.tablesorter.defaults, settings);
1834                    // store common expression for speed
1835                    $this = $(this);
1836                    // save the settings where they read
1837                    $.data(this, "tablesorter", config);
1838                    // build headers
1839                    $headers = buildHeaders(this);
1840                    // try to auto detect column type, and store in tables config
1841                    this.config.parsers = buildParserCache(this, $headers);
1842                    // build the cache for the tbody cells
1843                    cache = buildCache(this);
1844                    // get the css class names, could be done else where.
1845                    var sortCSS = [config.cssDesc, config.cssAsc];
1846                    // fixate columns if the users supplies the fixedWidth option
1847                    fixColumnWidth(this);
1848                    // apply event handling to headers
1849                    // this is to big, perhaps break it out?
1850                    $headers.click(
1851
1852                    function (e) {
1853                        var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0;
1854                        if (!this.sortDisabled && totalRows > 0) {
1855                            // Only call sortStart if sorting is
1856                            // enabled.
1857                            $this.trigger("sortStart");
1858                            // store exp, for speed
1859                            var $cell = $(this);
1860                            // get current column index
1861                            var i = this.column;
1862                            // get current column sort order
1863                            this.order = this.count++ % 2;
1864							// always sort on the locked order.
1865							if(this.lockedOrder) this.order = this.lockedOrder;
1866							
1867							// user only whants to sort on one
1868                            // column
1869                            if (!e[config.sortMultiSortKey]) {
1870                                // flush the sort list
1871                                config.sortList = [];
1872                                if (config.sortForce != null) {
1873                                    var a = config.sortForce;
1874                                    for (var j = 0; j < a.length; j++) {
1875                                        if (a[j][0] != i) {
1876                                            config.sortList.push(a[j]);
1877                                        }
1878                                    }
1879                                }
1880                                // add column to sort list
1881                                config.sortList.push([i, this.order]);
1882                                // multi column sorting
1883                            } else {
1884                                // the user has clicked on an all
1885                                // ready sortet column.
1886                                if (isValueInArray(i, config.sortList)) {
1887                                    // revers the sorting direction
1888                                    // for all tables.
1889                                    for (var j = 0; j < config.sortList.length; j++) {
1890                                        var s = config.sortList[j],
1891                                            o = config.headerList[s[0]];
1892                                        if (s[0] == i) {
1893                                            o.count = s[1];
1894                                            o.count++;
1895                                            s[1] = o.count % 2;
1896                                        }
1897                                    }
1898                                } else {
1899                                    // add column to sort list array
1900                                    config.sortList.push([i, this.order]);
1901                                }
1902                            };
1903                            setTimeout(function () {
1904                                // set css for headers
1905                                setHeadersCss($this[0], $headers, config.sortList, sortCSS);
1906                                appendToTable(
1907	                                $this[0], multisort(
1908	                                $this[0], config.sortList, cache)
1909								);
1910                            }, 1);
1911                            // stop normal event by returning false
1912                            return false;
1913                        }
1914                        // cancel selection
1915                    }).mousedown(function () {
1916                        if (config.cancelSelection) {
1917                            this.onselectstart = function () {
1918                                return false
1919                            };
1920                            return false;
1921                        }
1922                    });
1923                    // apply easy methods that trigger binded events
1924                    $this.bind("update", function () {
1925                        var me = this;
1926                        setTimeout(function () {
1927                            // rebuild parsers.
1928                            me.config.parsers = buildParserCache(
1929                            me, $headers);
1930                            // rebuild the cache map
1931                            cache = buildCache(me);
1932                        }, 1);
1933                    }).bind("updateCell", function (e, cell) {
1934                        var config = this.config;
1935                        // get position from the dom.
1936                        var pos = [(cell.parentNode.rowIndex - 1), cell.cellIndex];
1937                        // update cache
1938                        cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format(
1939                        getElementText(config, cell), cell);
1940                    }).bind("sorton", function (e, list) {
1941                        $(this).trigger("sortStart");
1942                        config.sortList = list;
1943                        // update and store the sortlist
1944                        var sortList = config.sortList;
1945                        // update header count index
1946                        updateHeaderSortCount(this, sortList);
1947                        // set css for headers
1948                        setHeadersCss(this, $headers, sortList, sortCSS);
1949                        // sort the table and append it to the dom
1950                        appendToTable(this, multisort(this, sortList, cache));
1951                    }).bind("appendCache", function () {
1952                        appendToTable(this, cache);
1953                    }).bind("applyWidgetId", function (e, id) {
1954                        getWidgetById(id).format(this);
1955                    }).bind("applyWidgets", function () {
1956                        // apply widgets
1957                        applyWidget(this);
1958                    });
1959                    if ($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) {
1960                        config.sortList = $(this).metadata().sortlist;
1961                    }
1962                    // if user has supplied a sort list to constructor.
1963                    if (config.sortList.length > 0) {
1964                        $this.trigger("sorton", [config.sortList]);
1965                    }
1966                    // apply widgets
1967                    applyWidget(this);
1968                });
1969            };
1970            this.addParser = function (parser) {
1971                var l = parsers.length,
1972                    a = true;
1973                for (var i = 0; i < l; i++) {
1974                    if (parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
1975                        a = false;
1976                    }
1977                }
1978                if (a) {
1979                    parsers.push(parser);
1980                };
1981            };
1982            this.addWidget = function (widget) {
1983                widgets.push(widget);
1984            };
1985            this.formatFloat = function (s) {
1986                var i = parseFloat(s);
1987                return (isNaN(i)) ? 0 : i;
1988            };
1989            this.formatInt = function (s) {
1990                var i = parseInt(s);
1991                return (isNaN(i)) ? 0 : i;
1992            };
1993            this.isDigit = function (s, config) {
1994                // replace all an wanted chars and match.
1995                return /^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g, '')));
1996            };
1997            this.clearTableBody = function (table) {
1998                if ($.browser.msie) {
1999                    function empty() {
2000                        while (this.firstChild)
2001                        this.removeChild(this.firstChild);
2002                    }
2003                    empty.apply(table.tBodies[0]);
2004                } else {
2005                    table.tBodies[0].innerHTML = "";
2006                }
2007            };
2008        }
2009    });
2010
2011    // extend plugin scope
2012    $.fn.extend({
2013        tablesorter: $.tablesorter.construct
2014    });
2015
2016    // make shortcut
2017    var ts = $.tablesorter;
2018
2019    // add default parsers
2020    ts.addParser({
2021        id: "text",
2022        is: function (s) {
2023            return true;
2024        }, format: function (s) {
2025            return $.trim(s.toLocaleLowerCase());
2026        }, type: "text"
2027    });
2028
2029    ts.addParser({
2030        id: "digit",
2031        is: function (s, table) {
2032            var c = table.config;
2033            return $.tablesorter.isDigit(s, c);
2034        }, format: function (s) {
2035            return $.tablesorter.formatFloat(s);
2036        }, type: "numeric"
2037    });
2038
2039    ts.addParser({
2040        id: "currency",
2041        is: function (s) {
2042            return /^[£$€?.]/.test(s);
2043        }, format: function (s) {
2044            return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g), ""));
2045        }, type: "numeric"
2046    });
2047
2048    ts.addParser({
2049        id: "ipAddress",
2050        is: function (s) {
2051            return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);
2052        }, format: function (s) {
2053            var a = s.split("."),
2054                r = "",
2055                l = a.length;
2056            for (var i = 0; i < l; i++) {
2057                var item = a[i];
2058                if (item.length == 2) {
2059                    r += "0" + item;
2060                } else {
2061                    r += item;
2062                }
2063            }
2064            return $.tablesorter.formatFloat(r);
2065        }, type: "numeric"
2066    });
2067
2068    ts.addParser({
2069        id: "url",
2070        is: function (s) {
2071            return /^(https?|ftp|file):\/\/$/.test(s);
2072        }, format: function (s) {
2073            return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), ''));
2074        }, type: "text"
2075    });
2076
2077    ts.addParser({
2078        id: "isoDate",
2079        is: function (s) {
2080            return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);
2081        }, format: function (s) {
2082            return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(
2083            new RegExp(/-/g), "/")).getTime() : "0");
2084        }, type: "numeric"
2085    });
2086
2087    ts.addParser({
2088        id: "percent",
2089        is: function (s) {
2090            return /\%$/.test($.trim(s));
2091        }, format: function (s) {
2092            return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g), ""));
2093        }, type: "numeric"
2094    });
2095
2096    ts.addParser({
2097        id: "usLongDate",
2098        is: function (s) {
2099            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)))$/));
2100        }, format: function (s) {
2101            return $.tablesorter.formatFloat(new Date(s).getTime());
2102        }, type: "numeric"
2103    });
2104
2105    ts.addParser({
2106        id: "shortDate",
2107        is: function (s) {
2108            return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);
2109        }, format: function (s, table) {
2110            var c = table.config;
2111            s = s.replace(/\-/g, "/");
2112            if (c.dateFormat == "us") {
2113                // reformat the string in ISO format
2114                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2");
2115            } else if (c.dateFormat == "uk") {
2116                // reformat the string in ISO format
2117                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1");
2118            } else if (c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
2119                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3");
2120            }
2121            return $.tablesorter.formatFloat(new Date(s).getTime());
2122        }, type: "numeric"
2123    });
2124    ts.addParser({
2125        id: "time",
2126        is: function (s) {
2127            return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
2128        }, format: function (s) {
2129            return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime());
2130        }, type: "numeric"
2131    });
2132    ts.addParser({
2133        id: "metadata",
2134        is: function (s) {
2135            return false;
2136        }, format: function (s, table, cell) {
2137            var c = table.config,
2138                p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
2139            return $(cell).metadata()[p];
2140        }, type: "numeric"
2141    });
2142    // add default widgets
2143    ts.addWidget({
2144        id: "zebra",
2145        format: function (table) {
2146            if (table.config.debug) {
2147                var time = new Date();
2148            }
2149            var $tr, row = -1,
2150                odd;
2151            // loop through the visible rows
2152            $("tr:visible", table.tBodies[0]).each(function (i) {
2153                $tr = $(this);
2154                // style children rows the same way the parent
2155                // row was styled
2156                if (!$tr.hasClass(table.config.cssChildRow)) row++;
2157                odd = (row % 2 == 0);
2158                $tr.removeClass(
2159                table.config.widgetZebra.css[odd ? 0 : 1]).addClass(
2160                table.config.widgetZebra.css[odd ? 1 : 0])
2161            });
2162            if (table.config.debug) {
2163                $.tablesorter.benchmark("Applying Zebra widget", time);
2164            }
2165        }
2166    });
2167})(jQuery);
2168/*
2169 * jQuery JSONP Core Plugin 2.0.2 (2010-05-21)
2170 * 
2171 * http://code.google.com/p/jquery-jsonp/
2172 *
2173 * Copyright (c) 2010 Julian Aubourg
2174 *
2175 * This document is licensed as free software under the terms of the
2176 * MIT License: http://www.opensource.org/licenses/mit-license.php
2177 */
2178 
2179 /* 
2180   Sections marked OLD OPERA  indicate original 2.0.2 code.
2181   Lines immediately after are suggested by Daniel Bratell <[email protected]>.
2182   Old lines reflect Opera workarounds for the old Opera browser;
2183   the new Opera parser chokes up on those workarounds.
2184   */
2185   
2186 
2187 
2188( function( $ , setTimeout ) {
2189	
2190	// ###################### UTILITIES ##
2191	
2192	// Noop
2193	function noop() {
2194	}
2195	
2196	// Generic callback for firefox & opera
2197	function genericCallback( data ) {
2198		lastValue = [ data ];
2199	}
2200
2201	// Add script to document
2202	function appendScript( node ) {
2203		head.insertBefore( node , head.firstChild );
2204	}
2205	
2206	// Call if defined
2207	function callIfDefined( method , object , parameters ) {
2208		method && method.apply( object , parameters );
2209	}
2210	
2211	// Give joining character given url
2212	function qMarkOrAmp( url ) {
2213		return /\?/ .test( url ) ? "&" : "?";
2214	}
2215	
2216	var // String constants (for better minification)
2217		STR_ASYNC = "async",
2218		STR_EMPTY = "",
2219		STR_ERROR = "error",
2220		STR_JQUERY_JSONP = "_jqjsp",
2221		STR_ON = "on",
2222		STR_ONERROR = STR_ON + STR_ERROR,
2223		STR_ONLOAD = STR_ON + "load",
2224		STR_ONREADYSTATECHANGE = STR_ON + "readystatechange",
2225		STR_REMOVE_CHILD = "removeChild",
2226		STR_SCRIPT_TAG = "<script/>",
2227		STR_SUCCESS = "success",
2228		STR_TIMEOUT = "timeout",
2229		
2230		// Head element (for faster use)
2231		head = $( "head" )[ 0 ] || document.documentElement,
2232		// Page cache
2233		pageCache = {},
2234		// Counter
2235		count = 0,
2236		// Last returned value
2237		lastValue,
2238		
2239		// ###################### DEFAULT OPTIONS ##
2240		xOptionsDefaults = {
2241			//beforeSend: undefined,
2242			//cache: false,
2243			callback: STR_JQUERY_JSONP,
2244			//callbackParameter: undefined,
2245			//complete: undefined,
2246			//data: ""
2247			//dataFilter: undefined,
2248			//error: undefined,
2249			//pageCache: false,
2250			//success: undefined,
2251			//timeout: 0,
2252			//traditional: false,		
2253			url: location.href
2254		};
2255	
2256	// ###################### MAIN FUNCTION ##
2257	function jsonp( xOptions ) {
2258		
2259		// Build data with default
2260		xOptions = $.extend( {} , xOptionsDefaults , xOptions );
2261		
2262		// References to xOptions members (for better minification)
2263		var completeCallback = xOptions.complete,
2264			dataFilter = xOptions.dataFilter,
2265			callbackParameter = xOptions.callbackParameter,
2266			successCallbackName = xOptions.callback,
2267			cacheFlag = xOptions.cache,
2268			pageCacheFlag = xOptions.pageCache,
2269			url = xOptions.url,
2270			data = xOptions.data,
2271			timeout = xOptions.timeout,
2272			pageCached,
2273			
2274			// References to beforeSend (for better minification)
2275			beforeSendCallback = xOptions.beforeSend,
2276		
2277			// Abort/done flag
2278			done = 0,
2279			
2280			// Life-cycle functions
2281			cleanUp = noop;
2282		
2283		// Create the abort method
2284		xOptions.abort = function() { 
2285			! done++ &&	cleanUp(); 
2286		};
2287
2288		// Call beforeSend if provided (early abort if false returned)
2289		if ( beforeSendCallback
2290			&& ( beforeSendCallback( xOptions , xOptions ) === false || done ) ) {
2291			return xOptions;
2292		}
2293			
2294		// Control entries
2295		url = url || STR_EMPTY;
2296		data = data ? ( (typeof data) == "string" ? data : $.param( data , xOptions.traditional ) ) : STR_EMPTY;
2297			
2298		// Build final url
2299		url += data ? ( qMarkOrAmp( url ) + data ) : STR_EMPTY;
2300		
2301		// Add callback parameter if provided as option
2302		callbackParameter && ( url += qMarkOrAmp( url ) + escape(callbackParameter) + "=?" );
2303		
2304		// Add anticache parameter if needed
2305		! cacheFlag && ! pageCacheFlag && ( url += qMarkOrAmp( url ) + "_" + ( new Date() ).getTime() + "=" );
2306		
2307		// Replace last ? by callback parameter
2308		url = url.replace( /=\?(&|$)/ , "=" + successCallbackName + "$1" );
2309		
2310		// Success notifier
2311		function notifySuccess( json ) {
2312			! done++ && setTimeout( function() {
2313				cleanUp();
2314				// Pagecache if needed
2315				pageCacheFlag && ( pageCache [ url ] = { s: [ json ] } );
2316				// Apply the data filter if provided
2317				dataFilter && ( json = dataFilter.apply( xOptions , [ json ] ) );
2318				// Call success then complete
2319				callIfDefined( xOptions.success , xOptions , [ json , STR_SUCCESS ] );
2320				callIfDefined( completeCallback , xOptions , [ xOptions , STR_SUCCESS ] );
2321			} , 0 );
2322		}
2323		
2324		// Error notifier
2325	    function notifyError( type ) {
2326	    	! done++ && setTimeout( function() {
2327	    		// Clean up
2328	    		cleanUp();
2329				// If pure error (not timeout), cache if needed
2330				pageCacheFlag && type != STR_TIMEOUT && ( pageCache[ url ] = type );
2331				// Call error then complete
2332				callIfDefined( xOptions.error , xOptions , [ xOptions , type ] );
2333				callIfDefined( completeCallback , xOptions , [ xOptions , type ] );
2334	    	} , 0 );
2335	    }
2336	    
2337		// Check page cache
2338		pageCacheFlag && ( pageCached = pageCache[ url ] ) 
2339			? ( pageCached.s ? notifySuccess( pageCached.s[ 0 ] ) : notifyError( pageCached ) )
2340			:
2341			// Initiate request
2342			setTimeout( function( script , scriptAfter , timeoutTimer ) {
2343				
2344				if ( ! done ) {
2345				
2346					// If a timeout is needed, install it
2347					timeoutTimer = timeout > 0 && setTimeout( function() {
2348						notifyError( STR_TIMEOUT );
2349					} , timeout );
2350					
2351					// Re-declare cleanUp function
2352					cleanUp = function() {
2353						timeoutTimer && clearTimeout( timeoutTimer );
2354						script[ STR_ONREADYSTATECHANGE ]
2355							= script[ STR_ONLOAD ]
2356							= script[ STR_ONERROR ]
2357							= null;
2358						head[ STR_REMOVE_CHILD ]( script );
2359						// OLD OPERA: scriptAfter && head[ STR_REMOVE_CHILD ]( scriptAfter );
2360						scriptAfter && scriptAfter.parentNode && head[ STR_REMOVE_CHILD ]( scriptAfter );
2361						
2362					};
2363					
2364					// Install the generic callback
2365					// (BEWARE: global namespace pollution ahoy)
2366					window[ successCallbackName ] = genericCallback;
2367
2368					// Create the script tag
2369					script = $( STR_SCRIPT_TAG )[ 0 ];
2370					
2371					// Callback function
2372					function callback( result ) {
2373						result = lastValue;
2374						lastValue = undefined;
2375						result ? notifySuccess( result[ 0 ] ) : notifyError( STR_ERROR );
2376					}
2377										
2378					// IE: onreadystatechange handler
2379					script[ STR_ONREADYSTATECHANGE ] = function() {
2380					
2381						/loaded|complete/.test( script.readyState ) && callback();
2382						
2383					};
2384					
2385					// All: standard handlers
2386					script[ STR_ONERROR ] = script[ STR_ONLOAD ] = callback;
2387					
2388					//ORIGINAL: $.browser.opera ?
2389					// NOW NEEDS MOOTOOLS
2390					Browser.opera ? 
2391						
2392						// Opera: onerror is not called, use synchronized script execution
2393						( ( scriptAfter = $( STR_SCRIPT_TAG )[ 0 ] ).text = "jQuery('#" + ( script.id = STR_JQUERY_JSONP + count++ ) + "')[0]." + STR_ONERROR + "()" )
2394						
2395						// Firefox: set script as async to avoid blocking scripts
2396						: script[ STR_ASYNC ] = STR_ASYNC;
2397						
2398					;
2399					
2400					// Set source
2401					script.src = url;
2402					
2403					// Append main script
2404					appendScript( script );
2405					
2406					// Opera: Append trailing script
2407					// OLD OPERA: scriptAfter && appendScript( scriptAfter );
2408					setTimeout(function(){scriptAfter && appendScript( scriptAfter )},1000);
2409				}
2410				
2411			} , 0 );
2412		
2413		return xOptions;
2414	}
2415	
2416	// ###################### SETUP FUNCTION ##
2417	jsonp.setup = function( xOptions ) {
2418		$.extend( xOptionsDefaults , xOptions );
2419	};
2420
2421	// ###################### INSTALL in jQuery ##
2422	$.jsonp = jsonp;
2423	
2424} )( jQuery , setTimeout );
2425/*
2426 * jQuery MD5 Plugin 1.2.1
2427 * https://github.com/blueimp/jQuery-MD5
2428 *
2429 * Copyright 2010, Sebastian Tschan
2430 * https://blueimp.net
2431 *
2432 * Licensed under the MIT license:
2433 * http://creativecommons.org/licenses/MIT/
2434 * 
2435 * Based on
2436 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
2437 * Digest Algorithm, as defined in RFC 1321.
2438 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
2439 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
2440 * Distributed under the BSD License
2441 * See http://pajhome.org.uk/crypt/md5 for more info.
2442 */
2443
2444/*jslint bitwise: true */
2445/*global unescape, jQuery */
2446
2447(function ($) {
2448    'use strict';
2449
2450    /*
2451    * Add integers, wrapping at 2^32. This uses 16-bit operations internally
2452    * to work around bugs in some JS interpreters.
2453    */
2454    function safe_add(x, y) {
2455        var lsw = (x & 0xFFFF) + (y & 0xFFFF),
2456            msw = (x >> 16) + (y >> 16) + (lsw >> 16);
2457        return (msw << 16) | (lsw & 0xFFFF);
2458    }
2459
2460    /*
2461    * Bitwise rotate a 32-bit number to the left.
2462    */
2463    function bit_rol(num, cnt) {
2464        return (num << cnt) | (num >>> (32 - cnt));
2465    }
2466
2467    /*
2468    * These functions implement the four basic operations the algorithm uses.
2469    */
2470    function md5_cmn(q, a, b, x, s, t) {
2471        return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
2472    }
2473    function md5_ff(a, b, c, d, x, s, t) {
2474        return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
2475    }
2476    function md5_gg(a, b, c, d, x, s, t) {
2477        return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
2478    }
2479    function md5_hh(a, b, c, d, x, s, t) {
2480        return md5_cmn(b ^ c ^ d, a, b, x, s, t);
2481    }
2482    function md5_ii(a, b, c, d, x, s, t) {
2483        return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
2484    }
2485
2486    /*
2487    * Calculate the MD5 of an array of little-endian words, and a bit length.
2488    */
2489    function binl_md5(x, len) {
2490        /* append padding */
2491        x[len >> 5] |= 0x80 << ((len) % 32);
2492        x[(((len + 64) >>> 9) << 4) + 14] = len;
2493
2494        var i, olda, oldb, oldc, oldd,
2495            a =  1732584193,
2496            b = -271733879,
2497            c = -1732584194,
2498            d =  271733878;
2499
2500        for (i = 0; i < x.length; i += 16) {
2501            olda = a;
2502            oldb = b;
2503            oldc = c;
2504            oldd = d;
2505
2506            a = md5_ff(a, b, c, d, x[i],       7, -680876936);
2507            d = md5_ff(d, a, b, c, x[i +  1], 12, -389564586);
2508            c = md5_ff(c, d, a, b, x[i +  2], 17,  606105819);
2509            b = md5_ff(b, c, d, a, x[i +  3], 22, -1044525330);
2510            a = md5_ff(a, b, c, d, x[i +  4],  7, -176418897);
2511            d = md5_ff(d, a, b, c, x[i +  5], 12,  1200080426);
2512            c = md5_ff(c, d, a, b, x[i +  6], 17, -1473231341);
2513            b = md5_ff(b, c, d, a, x[i +  7], 22, -45705983);
2514            a = md5_ff(a, b, c, d, x[i +  8],  7,  1770035416);
2515            d = md5_ff(d, a, b, c, x[i +  9], 12, -1958414417);
2516            c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
2517            b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
2518            a = md5_ff(a, b, c, d, x[i + 12],  7,  1804603682);
2519            d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
2520            c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
2521            b = md5_ff(b, c, d, a, x[i + 15], 22,  1236535329);
2522
2523            a = md5_gg(a, b, c, d, x[i +  1],  5, -165796510);
2524            d = md5_gg(d, a, b, c, x[i +  6],  9, -1069501632);
2525            c = md5_gg(c, d, a, b, x[i + 11], 14,  643717713);
2526            b = md5_gg(b, c, d, a, x[i],      20, -373897302);
2527            a = md5_gg(a, b, c, d, x[i +  5],  5, -701558691);
2528            d = md5_gg(d, a, b, c, x[i + 10],  9,  38016083);
2529            c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
2530            b = md5_gg(b, c, d, a, x[i +  4], 20, -405537848);
2531            a = md5_gg(a, b, c, d, x[i +  9],  5,  568446438);
2532            d = md5_gg(d, a, b, c, x[i + 14],  9, -1019803690);
2533            c = md5_gg(c, d, a, b, x[i +  3], 14, -187363961);
2534            b = md5_gg(b, c, d, a, x[i +  8], 20,  1163531501);
2535            a = md5_gg(a, b, c, d, x[i + 13],  5, -1444681467);
2536            d = md5_gg(d, a, b, c, x[i +  2],  9, -51403784);
2537            c = md5_gg(c, d, a, b, x[i +  7], 14,  1735328473);
2538            b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
2539
2540            a = md5_hh(a, b, c, d, x[i +  5],  4, -378558);
2541            d = md5_hh(d, a, b, c, x[i +  8], 11, -2022574463);
2542            c = md5_hh(c, d, a, b, x[i + 11], 16,  1839030562);
2543            b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
2544            a = md5_hh(a, b, c, d, x[i +  1],  4, -1530992060);
2545            d = md5_hh(d, a, b, c, x[i +  4], 11,  1272893353);
2546            c = md5_hh(c, d, a, b, x[i +  7], 16, -155497632);
2547            b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
2548            a = md5_hh(a, b, c, d, x[i + 13],  4,  681279174);
2549            d = md5_hh(d, a, b, c, x[i],      11, -358537222);
2550            c = md5_hh(c, d, a, b, x[i +  3], 16, -722521979);
2551            b = md5_hh(b, c, d, a, x[i +  6], 23,  76029189);
2552            a = md5_hh(a, b, c, d, x[i +  9],  4, -640364487);
2553            d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
2554            c = md5_hh(c, d, a, b, x[i + 15], 16,  530742520);
2555            b = md5_hh(b, c, d, a, x[i +  2], 23, -995338651);
2556
2557            a = md5_ii(a, b, c, d, x[i],       6, -198630844);
2558            d = md5_ii(d, a, b, c, x[i +  7], 10,  1126891415);
2559            c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
2560            b = md5_ii(b, c, d, a, x[i +  5], 21, -57434055);
2561            a = md5_ii(a, b, c, d, x[i + 12],  6,  1700485571);
2562            d = md5_ii(d, a, b, c, x[i +  3], 10, -1894986606);
2563            c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
2564            b = md5_ii(b, c, d, a, x[i +  1], 21, -2054922799);
2565            a = md5_ii(a, b, c, d, x[i +  8],  6,  1873313359);
2566            d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
2567            c = md5_ii(c, d, a, b, x[i +  6], 15, -1560198380);
2568            b = md5_ii(b, c, d, a, x[i + 13], 21,  1309151649);
2569            a = md5_ii(a, b, c, d, x[i +  4],  6, -145523070);
2570            d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
2571            c = md5_ii(c, d, a, b, x[i +  2], 15,  718787259);
2572            b = md5_ii(b, c, d, a, x[i +  9], 21, -343485551);
2573
2574            a = safe_add(a, olda);
2575            b = safe_add(b, oldb);
2576            c = safe_add(c, oldc);
2577            d = safe_add(d, oldd);
2578        }
2579        return [a, b, c, d];
2580    }
2581
2582    /*
2583    * Convert an array of little-endian words to a string
2584    */
2585    function binl2rstr(input) {
2586        var i,
2587            output = '';
2588        for (i = 0; i < input.length * 32; i += 8) {
2589            output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
2590        }
2591        return output;
2592    }
2593
2594    /*
2595    * Convert a raw string to an array of little-endian words
2596    * Characters >255 have their high-byte silently ignored.
2597    */
2598    function rstr2binl(input) {
2599        var i,
2600            output = [];
2601        output[(input.length >> 2) - 1] = undefined;
2602        for (i = 0; i < output.length; i += 1) {
2603            output[i] = 0;
2604        }
2605        for (i = 0; i < input.length * 8; i += 8) {
2606            output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
2607        }
2608        return output;
2609    }
2610
2611    /*
2612    * Calculate the MD5 of a raw string
2613    */
2614    function rstr_md5(s) {
2615        return binl2rstr(binl_md5(rstr2binl(s), s.length * 8));
2616    }
2617
2618    /*
2619    * Calculate the HMAC-MD5, of a key and some data (raw strings)
2620    */
2621    function rstr_hmac_md5(key, data) {
2622        var i,
2623            bkey = rstr2binl(key),
2624            ipad = [],
2625            opad = [],
2626            hash;
2627        ipad[15] = opad[15] = undefined;                        
2628        if (bkey.length > 16) {
2629            bkey = binl_md5(bkey, key.length * 8);
2630        }
2631        for (i = 0; i < 16; i += 1) {
2632            ipad[i] = bkey[i] ^ 0x36363636;
2633            opad[i] = bkey[i] ^ 0x5C5C5C5C;
2634        }
2635        hash = binl_md5(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
2636        return binl2rstr(binl_md5(opad.concat(hash), 512 + 128));
2637    }
2638
2639    /*
2640    * Convert a raw string to a hex string
2641    */
2642    function rstr2hex(input) {
2643        var hex_tab = '0123456789abcdef',
2644            output = '',
2645            x,
2646            i;
2647        for (i = 0; i < input.length; i += 1) {
2648            x = input.charCodeAt(i);
2649            output += hex_tab.charAt((x >>> 4) & 0x0F) +
2650                hex_tab.charAt(x & 0x0F);
2651        }
2652        return output;
2653    }
2654
2655    /*
2656    * Encode a string as utf-8
2657    */
2658    function str2rstr_utf8(input) {
2659        return unescape(encodeURIComponent(input));
2660    }
2661
2662    /*
2663    * Take string arguments and return either raw or hex encoded strings
2664    */
2665    function raw_md5(s) {
2666        return rstr_md5(str2rstr_utf8(s));
2667    }
2668    function hex_md5(s) {
2669        return rstr2hex(raw_md5(s));
2670    }
2671    function raw_hmac_md5(k, d) {
2672        return rstr_hmac_md5(str2rstr_utf8(k), str2rstr_utf8(d));
2673    }
2674    function hex_hmac_md5(k, d) {
2675        return rstr2hex(raw_hmac_md5(k, d));
2676    }
2677    
2678    $.md5 = function (string, key, raw) {
2679        if (!key) {
2680            if (!raw) {
2681                return hex_md5(string);
2682            } else {
2683                return raw_md5(string);
2684            }
2685        }
2686        if (!raw) {
2687            return hex_hmac_md5(key, string);
2688        } else {
2689            return raw_hmac_md5(key, string);
2690        }
2691    };
2692    
2693}(typeof jQuery === 'function' ? jQuery : this));
2694
2695// test-ipv6.com javascript
2696var dummyConsole = [];
2697var console = console || {};
2698if (!console.log) {
2699  console.log = function (message) {
2700    dummyConsole.push(message);
2701  };
2702}
2703                
2704
2705/*global GIGO, MirrorConfig, $gt, jQuery,  window,  alert,  Browser */
2706
2707/* TODO consider having something on the debug screen for missing variables */
2708
2709GIGO.mirrorconfig = function (key1, key2, fallback) {
2710    var ret;
2711    try {
2712        ret = MirrorConfig[key1][key2];
2713        if (typeof ret === "undefined") {
2714          ret = fallback;
2715        }
2716    } catch (e) {
2717        ret = fallback;
2718    }
2719    return ret;
2720};
2721
2722/* Look for <span lookup=site.name>x</span> and replace "x" wih the config.js values */
2723
2724GIGO.fix_logo_as_html = function () {
2725    if (MirrorConfig.footer.html) {
2726        jQuery("#logo").load(MirrorConfig.footer.html);
2727    }
2728};
2729
2730GIGO.fix_logo_generic = function () {
2731    // logo, operator, link
2732    if (MirrorConfig.footer.logo || MirrorConfig.footer.operator) {
2733        if (MirrorConfig.footer.logo) {
2734            jQuery("#logo_img").append(jQuery("<img>", {
2735                src: MirrorConfig.footer.logo
2736            }));
2737        }
2738        if (MirrorConfig.footer.operator) {
2739            if (MirrorConfig.footer.transparent) {
2740              jQuery("#logo_operator").append("This instance of test-ipv6.com is provided by " + " ");
2741            } else {
2742              jQuery("#logo_operator").append("This mirror is provided by" + " ");
2743            }
2744            if (MirrorConfig.footer.link) {
2745                jQuery("#logo_operator").append(jQuery("<a>", {
2746                    text: MirrorConfig.footer.operator,
2747                    href: MirrorConfig.footer.link,
2748                    target: "_blank"
2749                }));
2750            } else {
2751                jQuery("#logo_operator").append(jQuery("<span>").text(MirrorConfig.footer.operator));
2752            }
2753        }
2754    }
2755};
2756
2757
2758// This is called very late, after the test completes
2759// but before "Other Sites" are checked.  We will by default
2760// wait until "late", to avoid interfering with the
2761// actual tests, since those are purely timing based.
2762GIGO.fix_footer_late = function () {
2763    if (MirrorConfig.footer) {
2764      if (!(MirrorConfig.footer.early)) {
2765        GIGO.fix_logo_as_html();
2766        GIGO.fix_logo_generic();
2767      }
2768    }
2769};
2770
2771// This is called very early into the site startup.
2772// This gives the option of displaying any footer information
2773// at the risk of interfering with results.
2774GIGO.fix_footer_early = function() {
2775
2776
2777
2778
2779    if (MirrorConfig.footer) {
2780      if (MirrorConfig.footer.early) {
2781        GIGO.fix_logo_as_html();
2782        GIGO.fix_logo_generic();
2783      }
2784    }
2785};
2786
2787
2788GIGO.fixup_html_per_site_config = function () {
2789    var key1, key2, find, sel;
2790    // First, do search/replace stuff.
2791    for (key1 in MirrorConfig) {
2792        if (MirrorConfig.hasOwnProperty(key1)) {
2793            for (key2 in MirrorConfig[key1]) {
2794                if (MirrorConfig[key1].hasOwnProperty(key2)) {
2795                    find = key1 + "." + key2;
2796                    sel = "span[lookup='" + find + "']";
2797                    jQuery(sel).text(MirrorConfig[key1][key2]);
2798
2799                    sel = "div[lookup='" + find + "']";
2800                    jQuery(sel).html(MirrorConfig[key1][key2]);
2801
2802                    sel = "a[linkup='" + find + "']";
2803                    jQuery(sel).attr("href", MirrorConfig[key1][key2]);
2804
2805                    sel = "img[src='" + find + "']";
2806                    jQuery(sel).attr("src", MirrorConfig[key1][key2]);
2807
2808                    sel = "a[mailto='" + find + "']";
2809                    jQuery(sel).attr("href", "mailto:" + MirrorConfig[key1][key2]);
2810
2811
2812                }
2813            }
2814        }
2815    }
2816
2817};
2818
2819
2820GIGO.fixup_html_per_locale = function () {
2821
2822  if (/bot|google|baidu|bing|msn|duckduckgo|teoma|slurp|yandex/i.test(navigator.userAgent)) {
2823    console.log("skipping link fixup (crawler)");
2824    return;
2825  }
2826
2827
2828  $('a').each(function() {
2829    var value = $(this).attr('href');
2830    // if value starts with "/" and ends in .html .. fix it.
2831    if (value === "/") {
2832      value="/index.html";
2833    }
2834
2835    if (value.startsWith("/") && value.endsWith(".html")) {
2836        value=value+'.en_US';
2837        $(this).attr('href',value);
2838        //console.log("fixup_html_per_locale fixed href %o",value);
2839    }   
2840
2841  });
2842};
2843
2844
2845/*
2846** Report errors centrally, if not using IE6.
2847** Do this as a fake image fetch - avoids any risk
2848** of loading foreign code into the browser.
2849*/
2850window.onerror = function(message, url, linenumber) {
2851    var eurl;
2852    if (/\bMSIE 6/.test(navigator.userAgent) && !window.opera) {
2853        if (linenumber && parseInt(linenumber) < 100) {
2854            return;
2855        }
2856    }
2857    if (url && linenumber) {
2858        eurl = GIGO.protocol + "ds.main.test-ipv6.com/errors.php?";
2859        eurl = eurl + "message=" + encodeURIComponent(message);
2860        eurl = eurl + "&url=" + encodeURIComponent(url);
2861        eurl = eurl + "&linenumber=" + encodeURIComponent(linenumber);
2862        eurl = eurl + "&lang=" + encodeURIComponent("EN");
2863        eurl = eurl + "&version=" + encodeURIComponent("1.1.1033");
2864        new Image().src = eurl;
2865    }
2866    return false;
2867};
2868
2869
2870/*global GIGO, MirrorConfig, jQuery, alert, $gt */
2871/*jslint nomen: true */
2872
2873
2874GIGO.messages = {
2875    "bad": "bad",
2876    "ok": "ok",
2877    "slow": "slow",
2878    "timeout": "timeout",
2879    "skipped": "skipped",
2880
2881    "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.",
2882    "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.",
2883    "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.",
2884    "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.",
2885    "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).",
2886    "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.",
2887    "confused:NOASK": "Test results inconclusive; they were not consistent with expectations. Please rerun the test, and if the results are the same, seek local network help.",
2888    "dualstack:ipv4_preferred": "-",
2889    "dualstack:ipv6_preferred": "-",
2890    "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.",
2891    "ipv4_only": "You appear to be able to browse the IPv4 Internet only. You will not be able to reach IPv6-only sites.",
2892    "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.",
2893    "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.",
2894    "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.",
2895    "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.",
2896    "ipv6_only": "You appear to be able to browse the IPv6 Internet only. You have no access to IPv4. That\'s pretty bold!",
2897    "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.",
2898    "ipv6_timeout": "Connections to IPv6-only sites are timing out. Any web site that is IPv6 only, will appear to be down to you.",
2899    "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 IPv6 on your host.",
2900    "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.",
2901    "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.",
2902    "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.",
2903    "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.",
2904    "v6ns:ok": "Your DNS server (possibly run by your ISP) appears to have IPv6 Internet access.",
2905    "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.",
2906    "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.",
2907    "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.",
2908    "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>.",
2909    "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>.",
2910    "ipv4:no_address": "No IPv4 address detected",
2911    "ipv6:no_address": "No IPv6 address detected",
2912    "no_address": "Your IP address(es) could not be detected due to inteference from browser add-ons.",
2913    "opera": "The Opera web browser seems to be break on this site frequently. <b>If you have trouble, try another browser</b>.",
2914    "opera:turbo": "<b>Disable turbo mode on Opera, and try again.</b> Turbo mode is not compatible with the needs of this site.",
2915    "needs_ipv6": "To ensure the best Internet performance and connectivity, ask your ISP about native IPv6.",
2916    "dualstack:safe": "<b>Good news!</b> Your current configuration will continue to work as web sites enable IPv6.",
2917    "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>",
2918    "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>",
2919    "tunnel_6rd_dumb": "It appears that you use a managed tunnel mechanism, 6RD, to transport IPv6 over IPv4.",
2920    "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",
2921    "proxy_via_dumb": "We have detected that you are using a proxy. This means we are testing your proxy server, not your computer.",
2922    "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.",
2923    "broken": "We have suggestions to help you fix your system.",
2924    "sites": "Since you have IPv6, we are including a tab that shows how well you can reach other IPv6 sites. %sites",
2925    "avoids_ipv6": "Your browser has real working IPv6 address - but is avoiding using it. We\'re concerned about this.",
2926    "ood":"This mirror has been marked as out of compliance; you should instead visit <a href=\'//test-ipv6.com/\'>test-ipv6.com</a>."
2927};
2928
2929GIGO.messages_popups = {
2930// These are not just strings, but arrays,
2931// #1: url
2932// #2: link text to show (translate this!)
2933// Between the first and second string, there must be a comma and a space.
2934    "dualstack:mtu": ["faq_pmtud.html", "faq: MTU"],
2935    "IPv6 MTU": ["faq_pmtud.html", "faq: MTU"],
2936//    "ipv4:no_address": ["faq_ipv4_only.html", "faq: No IPv4"],
2937"ipv6:no_address": ["faq_no_ipv6.html", "faq: No IPv6"],
2938"needs_ipv6": ["faq_no_ipv6.html", "faq: No IPv6"],
2939    "6to4": ["faq_6to4.html", "faq: 6to4"],
2940    "teredo-minimum": ["faq_teredo_minimum.html", "faq: Teredo Minimum"],
2941    "v6ns:bad": ["faq_v6ns_bad.html", "faq: v6ns Bad"],
2942    "webfilter:blocked":  ["faq_browser_plugins.html", "faq: Browser Plugins"],
2943    "webfilter:dsboth":   ["faq_browser_plugins.html", "faq: Browser Plugins"],
2944    "webfilter:firefox":  ["faq_firefox_plugins.html", "faq: Firefox Add-Ons"],
2945    "webfilter:addons":   ["faq_browser_plugins.html", "faq: Browser Plugins"],
2946    "ip_timeout:firefox": ["faq_firefox_plugins.html", "faq: Firefox Add-Ons"],
2947    "opera": ["faq_opera.html", "faq: Opera"],
2948    "broken": ["broken.html", "faq: Broken!"],
2949    "ipv6:nodns": ["faq_broken_aaaa.html", "faq: Broken DNS Lookups"],
2950    "avoids_ipv6": ["faq_avoids_ipv6.html", "faq: Avoiding IPv6?"],
2951    "tunnel_6rd_dumb": ["faq_tunnel_6rd.html", "faq: 6RD tunnel"],
2952    "tls_warning" : ["faq_https.html","faq: Using HTTPS"],
2953    "tls_beta" : ["faq_https.html","faq: Using HTTPS"],
2954    "tls_available" : ["faq_https.html","faq: Using HTTPS"]
2955};
2956
2957
2958
2959/*global GIGO, jQuery, alert, $gt:true*/
2960
2961/* Used to fetch external strings, to make localization a bit easier. */
2962
2963GIGO.gettext = function (a, b) {
2964    var c;
2965    try {
2966        c = GIGO.gettext_messages[a][b];
2967    } catch (e) {
2968        return "[NO TEXT: " + a + " " + b + "]";
2969    }
2970    if (c) {
2971        return c;
2972    }
2973    return "[NO TEXT: " + a + " " + b + "]";
2974};
2975
2976/* global $gt(a,b) polution - for gettext */
2977$gt = GIGO.gettext;
2978
2979$gt = function () {
2980    console.log("whoops still using $gt");
2981};
2982
2983
2984// Original source:
2985// http://geekswithblogs.net/svanvliet/archive/2006/03/23/simple-javascript-object-dump-function.aspx
2986// Modified for:
2987//  GIGO name space
2988//  Wrapper function
2989/*global GIGO, jQuery, window, top */
2990/*jslint nomen: true */
2991/*jslint browser: true */
2992
2993
2994
2995
2996GIGO.dumpObj = function (obj, name) {
2997    var s = GIGO._dumpObj(obj, name, "  ", 0);
2998    s = jQuery('<div/>').text(s).html();
2999    GIGO.writeConsole("<pre>" + s + "</pre>");
3000};
3001
3002
3003GIGO._dumpObj_MAX_DUMP_DEPTH = 3;
3004
3005GIGO._dumpObj = function (obj, name, indent, depth) { /*jslint forin: false */
3006
3007    var s = JSON.stringify(obj,null,"  ");
3008    return s;
3009    
3010  // The rest of this is obsolete
3011  // (needs to be proven)
3012    var child, output, item;
3013    if (depth > GIGO._dumpObj_MAX_DUMP_DEPTH) {
3014        return indent + name + ": <Maximum Depth Reached>\n";
3015    }
3016    if (typeof obj === "object") {
3017        child = null;
3018        output = indent + name + "\n";
3019        indent += "\t";
3020        for (item in obj) {
3021            if (obj.hasOwnProperty(item)) {
3022
3023
3024                try {
3025                    child = obj[item];
3026                } catch (e) {
3027                    child = "<Unable to Evaluate>";
3028                }
3029                if (typeof child === "object") {
3030                    output += GIGO._dumpObj(child, item, indent, depth + 1);
3031                } else {
3032                    output += indent + item + ": " + child + "\n";
3033                }
3034            }
3035        }
3036        return output;
3037    }
3038    return obj;
3039};
3040
3041// From http://www.javascripter.net/faq/writingt.htm
3042// Use this instead of "alert"; you can scroll the window this produces.
3043// It also sucks a bit less CPU generating this output, since
3044// a real browser window was designed for large output.
3045GIGO.writeConsole = function (content) {
3046    top.consoleRef = window.open('', 'myconsole', 'width=550,height=450' + ',menubar=1' + ',toolbar=1' + ',status=1' 
3046+ ',scrollbars=1' + ',resizable=1');
3047    top.consoleRef.document.writeln('<html><head><title>Console</title></head>' + '<body bgcolor=white onLoad="self.focus()">' + content + '</body></html>');
3048    top.consoleRef.document.close();
3049};
3050
3051/*global GIGO, Browser, unescape */
3052/*jslint browser: true */
3053
3054GIGO.getms = function () {
3055    // Helper function to get the current date/time as milliseconds.
3056    var d = new Date();
3057    return d.getTime();
3058};
3059
3060
3061GIGO.slow = 5000; // milliseconds . If a test takes longer than this, it is considered "slow" (if good) or "timeout" (if error)
3062GIGO.max_time = 15 * 1000; // milliseconds . Max time to allow a test to try and run, before giving up on it.
3063GIGO.retry_until = 15 * 1000; // milliseconds.  If we want multiple passes, this says to stop new passes after this time.
3064GIGO.retry_min = 1; // Minimum time_ms to reload images, trying to differentiate service quality.
3065GIGO.retry_max = 3; // Max time_ms to allow reloading, no matter how fast.
3066GIGO.repeat_only_if_slow = 1; // If 1: only repeat tests if at least one test was slow.  If 0: always repeat until retry_min/retry_max.
3067GIGO.repeated = 0; // How many time_ms we've tried so far.
3068
3069GIGO.results = {}; // what we want to expose as "this" to callback functions
3070
3071
3072GIGO.results.ipv4 = {
3073    ip: "",
3074    subtype: ""
3075}; // Customer IP information, per our web service call
3076GIGO.results.ipv6 = {
3077    ip: "",
3078    subtype: ""
3079}; // Customer IP information, per our web service call
3080
3081GIGO.results.tests = {}; // Store test specific data here.
3082
3083GIGO.tabhistory = ["main"]; // History of what tab we go to and when; used for GIGO.goback()
3084
3085GIGO.tests_planned = 0; // As we add tests, this will be incremented.  Used by progress bar.
3086GIGO.tests_finished = 0; // As we finish tests, this will be incremented. Used by progress bar.
3087GIGO.start_time = GIGO.getms(); // Starting time.  Used by progress bar as well as by retry_until
3088GIGO.finished = 0; // When we're done with all tests, set to 1 to hide the progress bar
3089GIGO.slowcount = 0; // How many background jsonp we spawned so far. Used when we execute tasks in parallel to stagger load.
3090
3091// If we rig the test, don't report the results to the status surver.
3092// This is what happens when the page is called with
3093// ?test=oooooooo  (all "ok", and technically impossible).
3094// ?test=oobooooo  (more likely result)
3095// Main purpose is to test the display logic for given patterns of
3096// "ok", "slow", "bad", "timeout".
3097GIGO.test_rigged = 0;
3098
3099GIGO.tests = []; // The list of all tests we will run.
3100GIGO.queue = []; // If use_queue then this is the list of pending jobs to start.
3101GIGO.dequeued = []; // Tests we have dequeued
3102GIGO.use_queue = 0; // Set to 1 for force serial execution. Set to 0 to permit parallel execution.
3103if (Browser.firefox) {
3104    GIGO.use_queue = 1; // Always do serial execution for Firefox and friends, due to funky socks behavior.
3105}
3106if (Browser.opera) {
3107    GIGO.use_queue = 1; // Any blocking thread, blocks all.
3108    GIGO.max_time = 15 * 1000; // Hmm.
3109}
3110
3111GIGO.helpdesk = {}; // Test results will pass data to the helpdesk page
3112GIGO.helpdesk.other_sites = {};
3113GIGO.helpdesk.other_sites.finished = 0;
3114GIGO.helpdesk.other_sites.count = 0;
3115GIGO.helpdesk.other_sites.good = [];
3116GIGO.helpdesk.other_sites.bad = [];
3117
3118
3119// http://mootools.net/docs/core/Core/Browser
3120GIGO.slowcount_delay = 20; // How long (ms) to delay between backgrounding jsonp if use_queue==0
3121if (Browser.ie) {
3122    GIGO.slowcount_delay = 200; // Slow down spawning of ajax queries
3123}
3124
3125// Symbian appears to be particularly bad.
3126// DNS lookups for some people appear to slow things down by nearly 5 seconds
3127if (navigator.userAgent.match(/SymbianOS|SymbOS/)) {
3128    GIGO.slowcount_delay = 500; // Slow down on Symbian phones
3129    GIGO.slow = 9000;
3130}
3131
3132// What protocol (http, https) should we make our URLs?
3133// Force it into https:// or http:// (even though our inputs might say http or http:)
3134GIGO.protocol =   MirrorConfig.options.protocol ? MirrorConfig.options.protocol   : document.location.protocol;
3135GIGO.protocol = (GIGO.protocol.match(/https/))  ? "https://" : "http://";
3136GIGO.publishname = GIGO.protocol + GIGO.mirrorconfig("site", "name");
3137
3138
3139GIGO.parseGetVars = function () {
3140    var getVars, returnVars, i, newVar;
3141
3142
3143    getVars = location.search.substring(1).split("&"); // From the browser URL
3144    returnVars = [];
3145    i = 0;
3146
3147    for (i = 0; i < getVars.length; i = i + 1) {
3148        newVar = getVars[i].split("=");
3149        returnVars[unescape(newVar[0])] = unescape(newVar[1]);
3150    }
3151    return returnVars;
3152};
3153
3154
3155GIGO.CGI = GIGO.parseGetVars(); // Parse CGI arguements
3156GIGO.contact_wanted = GIGO.CGI.contact; // Do we want to force the contact form?
3157
3158console.log("GIGO.CGI=%o",GIGO.CGI);
3159
3160// If we found overrides, we will set GIGO.override
3161// as we as prepared each override into GIGO.overrides
3162GIGO.override = 0;
3163GIGO.overrides = {};
3164
3165
3166
3167if (!String.prototype.endsWith) {
3168    String.prototype.endsWith = function(searchString, position) {
3169        var subjectString = this.toString();
3170        if (typeof position !== "number" || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {
3171            position = subjectString.length;
3172        }
3173        position -= searchString.length;
3174        var lastIndex = subjectString.lastIndexOf(searchString, position);
3175        return lastIndex !== -1 && lastIndex === position;
3176    };
3177}
3178
3179GIGO.CheckHTTPS = function(s) {
3180    console.log("document protocol %o",document.location.protocol);
3181    return document.location.protocol.startsWith("https");
3182};
3183
3184GIGO.CheckTransparentDomain = function(s) {
3185    return s == "test-ipv6.com" || s.endsWith(".test-ipv6.com");
3186};
3187
3188GIGO.CheckTransparent = function() {
3189    if (GIGO.CheckTransparentDomain(document.location.hostname)) {
3190
3191        let og  = JSON.parse(JSON.stringify(MirrorConfig.options));
3192
3193
3194        // Bias the reporting location if the user is visiting a specific flavor of the site.
3195        let main = "main.test-ipv6.com"
3196        if (document.location.hostname.startsWith("ipv6.")) {
3197            main = "ipv6.main.test-ipv6.com";
3198        }
3199        if (document.location.hostname.startsWith("ipv4.")) {
3200            main = "ipv4.main.test-ipv6.com";
3201        }
3202        if (document.location.hostname.startsWith("ds.")) {
3203            main = "ds.main.test-ipv6.com";
3204        }
3205        console.log("document.location.hostname is %o",document.location.hostname);
3206        console.log("main is %o",main);
3207
3208
3209        // Always replace certain things when it's test-ipv6.com
3210        //delete MirrorConfig.footer.html;
3211        delete MirrorConfig.footer.logo;
3212        MirrorConfig.footer.transparent = 1;
3213        MirrorConfig.site = {
3214            name: "test-ipv6.com",
3215            contact: "Jason Fesler",
3216            mailto: "[email protected]",
3217            retire: true,
3218        };
3219        MirrorConfig.options.show_stats = GIGO.protocol + main + "/stats.html";
3220        MirrorConfig.options.comment_html = 1;
3221        MirrorConfig.options.userdata = main;
3222        MirrorConfig.options.comment=""; // no comments
3223        // Only replace these, if the underlying domain is something else.
3224        if (!GIGO.CheckTransparentDomain(MirrorConfig.load.domain)) {
3225            MirrorConfig.orig_options = og;
3226            MirrorConfig.options.survey = "/survey.php";
3227            MirrorConfig.options.comment = "/comment.php";
3228            MirrorConfig.options.userdata = main;
3229            MirrorConfig.options.v6mtu = "mtu1280." + MirrorConfig.load.domain;
3230        }
3231    }
3232    console.log("CheckTransparent: MirrorConfig is now %o",MirrorConfig);
3233};
3234
3235GIGO.CheckTransparent();
3236
3237/*global GIGO, MirrorConfig, jQuery,  Browser,  setTimeout,  alert, document */
3238/*jslint nomen: true */
3239/*jslint regexp: true */
3240
3241
3242GIGO.generate_share_link_entry = function (name, def) {
3243    var s, t, id, p;
3244    s = "";
3245    try {
3246        id = "test_" + name;
3247        t = GIGO.results.tests[id];
3248        if ((t.status === "ok") || (t.status === "slow")) {
3249            s = "&" + name + "=" + encodeURIComponent(t.status) + "," + encodeURIComponent(t.time_ms);
3250            p = t.ipinfo.type.replace(/^ipv/, "");
3251            s = s + "," + encodeURIComponent(p);
3252        }
3253        if ((t.status === "bad") || (t.status === "timeout")) {
3254            s = "&" + name + "=" + encodeURIComponent(t.status) + "," + encodeURIComponent(t.time_ms);
3255        }
3256    } catch (e) {
3257        noop = 1;
3258    }
3259    return s;
3260};
3261
3262
3263
3264GIGO.generate_share_link = function () {
3265    var url;
3266    url = location.href.replace(/[?#].*$/,'') + "?";
3267    if (GIGO.results.ipv4.ip) {
3268        url = url + "ip4=" + encodeURIComponent(GIGO.results.ipv4.ip);
3269    } else {
3270        url = url + "ip4=";
3271    }
3272    if (GIGO.results.ipv6.ip) {
3273        url = url + "&ip6=" + encodeURIComponent(GIGO.results.ipv6.ip).replace(/%3a/ig, ":");
3274    } else {
3275        url = url + "&ip6=";
3276    }
3277    url = url + GIGO.generate_share_link_entry("a", "4");
3278    url = url + GIGO.generate_share_link_entry("aaaa", "6");
3279    url = url + GIGO.generate_share_link_entry("ds", "6");
3280    url = url + GIGO.generate_share_link_entry("v6mtu", "6");
3281    url = url + GIGO.generate_share_link_entry("v6ns", "6");
3282    url = url + GIGO.generate_share_link_entry("dsmtu", "6");
3283
3284
3285    // Working/Failed sites
3286    if (GIGO.isdef(GIGO.failed_sites)) {
3287        url = url + "&failed_sites=" + GIGO.failed_sites.join(",");
3288    }
3289
3290    return url;
3291};
3292
3293
3294GIGO.show_share_link = function () {
3295    var url, a, t, te;
3296    url = GIGO.generate_share_link();
3297    a = jQuery("<a>");
3298
3299    t = jQuery("<p>");
3300    t.text(url);
3301    te = t.html();
3302    te = te.replace(/&amp;/g, "<wbr>&amp;");
3303    a.html(te);
3304    a.attr("href", url);
3305    a.attr("target", "_blank");
3306    d = jQuery("<p id=replayurl>").append(a);
3307    jQuery("#replayurl").replaceWith(d);
3308};
3309
3310GIGO.show_debug = function () {
3311    var s, url;
3312
3313    s = GIGO._dumpObj(GIGO.results.tests, "GIGO.results.tests.", "  ", 0);
3314    s = jQuery('<div/>').text(s).html();
3315    jQuery("#debug_dump").html("<pre>" + s + "</pre>");
3316
3317    GIGO.show_share_link();
3318};
3319
3320
3321// Some of our substitutions are expensive to compute.
3322// Let's just do it once.
3323GIGO.substitutions = {};
3324GIGO.substitutions.HTTPS = '<a href="' + "https://" +  document.location.hostname + document.location.pathname + '">HTTPS</a>';
3325
3326
3327// Return a table with left side colored and with a symbol; right side, informative text.
3328GIGO.results_table_wrapper = function (color, text) {
3329    var table;
3330    color = color.toLowerCase();
3331
3332    // Things we will do as substitutions
3333    text = text.replace("%HTTPS",GIGO.substitutions.HTTPS);
3334
3335    table = "";
3336    table = "<table class=\"results_wrapper\">";
3337    table = table + "<tr>";
3338
3339    table = table + "<td class=\"results_left\"><p style=\"margin: 0;\">";
3340
3341    switch (color) {
3342    case "green":
3343        table = table + '<img style="height: 2em; width: auto;" src="/images/hires_ok.png"/>';
3344        break;
3345    case "red":
3346        table = table + '<img style="height: 2em; width: auto;" src="/images/hires_bad.png"/>';
3347        break;
3348    case "blue":
3349        table = table + '<img style="height: 2em; width: auto;" src="/images/hires_info.png"/>';
3350        break;
3351    case "orange":
3352        table = table + '<img style="height: 2em; width: auto;" src="/images/hires_attention.png"/>';
3353        break;
3354    default:
3355        table = table + "&nbsp;";
3356        break;
3357    }
3358
3359    table = table + "</p></td>";
3360
3361    table = table + "<td class=\"results_right\">
3361" + text + "</td>";
3362    table = table + "</tr></table>";
3363
3364    return table;
3365};
3366
3367
3368GIGO.showdebug = function () {
3369    jQuery("#debuglink").show();
3370    GIGO.tabnav("debug");
3371};
3372
3373GIGO.start_sites = function () {
3374    var t, moreinfo, link, table;
3375    jQuery("#siteslink").show();
3376    GIGO.test_sites(2);
3377    t = "Since you have IPv6, we are including a tab that shows how well you can reach other IPv6 sites. %sites";
3378    moreinfo = "[more info]";
3379
3380    link = '<a href="#" class="help_popup" onclick="return GIGO.tabnav(\'sites\');">' + moreinfo + '</a>';
3381
3382    t = t.replace(/%sites/, link);
3383    table = GIGO.results_table_wrapper("blue", t);
3384    jQuery("#results_eof").before(table);
3385};
3386
3387
3388GIGO.update_ip = function (id) {
3389    // G = the GIGO object
3390    var s, ipinfo, escaped, name;
3391
3392    ipinfo = GIGO.results.tests[id].ipinfo;
3393
3394
3395    GIGO.show_debug();
3396
3397    if (GIGO.results.ipv4.ip !== "") {
3398        s = "Your IPv4 address on the public Internet appears to be" + " " + GIGO.results.ipv4.ip;
3399        if (GIGO.results.ipv4.subtype) {
3400            s = s + " (" + GIGO.results.ipv4.subtype + ")";
3401        }
3402        if (GIGO.results.ipv4.via) {
3403            s = s + "<br/>
3403" + "Proxied" + ", <code>" + jQuery('<div/>').text("Via: " + GIGO.results.ipv4.via).html() + "</code>";
3404        }
3405
3406        if ((GIGO.results.ipv4.asn_name) && (GIGO.results.ipv6.asn_name) && (GIGO.results.ipv4.asn_name !== GIGO.results.ipv6.asn_name)) {
3407            escaped = jQuery('<div/>').text(GIGO.results.ipv4.asn_name).html();
3408            s = s + "<br/>(" + escaped + ")";
3409            jQuery("#your_isp").html("");
3410        }
3411
3412        s = GIGO.results_table_wrapper("blue", s);
3413        jQuery("#your_ipv4").html(s);
3414    }
3415    if (GIGO.results.ipv6.ip !== "") {
3416        s = "Your IPv6 address on the public Internet appears to be" + " " + GIGO.results.ipv6.ip;
3417        if (GIGO.results.ipv6.subtype) {
3418            s = s + "<br/>" + "Your IPv6 service appears to be" + ": " + GIGO.results.ipv6.subtype;
3419        }
3420        if (GIGO.results.ipv6.via) {
3421            s = s + "<br/>" + "Proxied" + ", <code>" + jQuery('<div/>').text("Via: " + GIGO.results.ipv6.via).html() + "</code>";
3422        }
3423        if ((GIGO.results.ipv4.asn_name) && (GIGO.results.ipv6.asn_name) && (GIGO.results.ipv4.asn_name !== GIGO.results.ipv6.asn_name)) {
3424            escaped = jQuery('<div/>').text(GIGO.results.ipv6.asn_name).html();
3425            s = s + "<br/>(" + escaped + ")";
3426            jQuery("#your_isp").html("");
3427        }
3428        s = GIGO.results_table_wrapper("blue", s);
3429        jQuery("#your_ipv6").html(s);
3430    }
3431
3432    if (
3433        ((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))
3434    ) {
3435        name = GIGO.results.ipv4.asn_name || GIGO.results.ipv6.asn_name;
3436        escaped = jQuery('<div/>').text(name).html();
3437        s = "Your Internet Service Provider (ISP) appears to be" + " " + escaped;
3438        s = GIGO.results_table_wrapper("blue", s);
3439        jQuery("#your_isp").html(s);
3440    }
3441
3442
3443
3444
3445};
3446
3447
3448GIGO.update_status = function (id) {
3449    // G = the GIGO object
3450    // url = the URL we just received
3451    // id = the update we just received (ie, "test_a", "test_aaaa")
3452    // ipinfo.ip  = text form of ip;  ipinfo.type = "ipv4" or "ipv6";  ipinfo.subtype MAY say "Teredo" or "6to4"
3453    var status, status_translated, time_ms, ipinfo, content, url, proxied;
3454    status = GIGO.results.tests[id].status; // This should be ok/bad/slow/timeout
3455    status_translated = GIGO.messages[status];
3456    time_ms = GIGO.results.tests[id].time_ms; // This should be number of milliseconds spent
3457    ipinfo = GIGO.results.tests[id].ipinfo; // This may be "undef"
3458    url = GIGO.results.tests[id].url;
3459
3460    if (!time_ms) {
3461        content = "Started";
3462
3463    } else if (GIGO.isdef(ipinfo)) {
3464        // TODO: Localize number formats
3465        proxied = "";
3466        if (ipinfo.via) {
3467            proxied = " " + "proxied" + " ";
3468        }
3469
3470
3471
3472        content = "<span class=status_" + status + ">" + status_translated + "</span> " + "(" + (time_ms / 1000.0).toFixed(3) + "s) " + "using" + " " + proxied + ipinfo.type;
3473        if (ipinfo.subtype) {
3474            content = content + " " + ipinfo.subtype;
3475        }
3476        if (ipinfo.asn) {
3477            content = content + " ASN " + ipinfo.asn;
3478        }
3479    } else {
3480        // TODO: Localize number formats
3481        content = "<span class=status_" + status + ">" + status_translated + "</span> " + "(" + (time_ms / 1000.0).toFixed(3) + "s)";
3482    }
3483
3484    jQuery("#" + id).html(content);
3485    jQuery("#sum_" + id).html(content);
3486};
3487
3488GIGO.update_url = function (id) {
3489    var url, showurl, res;
3490    url = GIGO.results.tests[id].url;
3491    showurl = url.replace(/fill=xxxx*/, "fill=xxx...xxx"); // Obscene to show a nearly 2k url
3492    showurl = showurl.replace(/&testdomain=[^&]+&testname=[^&]+/,""); // Also remove the test name and test domain
3493    showurl = showurl.replace(/(gif|png|jpg)\?$/i,"$1"); // hmm
3494    res = id.replace(/test_/, "results_"); // Deterine which span to show this in
3495    jQuery("#" + res).html("<a id=url href='" + url + "'>" + showurl + " </a>");
3496};
3497
3498GIGO.browser_tweaks = function (G) {
3499    // Finish setting up the contact form
3500    if (Browser.Platform.win) {
3501        jQuery("#help_windows").show();
3502    } else if (Browser.Platform.linux) {
3503        jQuery("#help_linux").show();
3504    } else {
3505        jQuery("#help_generic").show();
3506    }
3507};
3508
3509GIGO.update_progress = function (G) {
3510    // G = the GIGO object
3511    // Now a spinner or "throbber" instead;
3512    // indicates how many tests have finished.
3513    // Prelude to being more flexible on dynamically adding tests.
3514    // Implements a progress bar
3515    // Based on:
3516    //     G.queue.length  - number of tests we have left to start
3517    //     G.dequeued.length - number of tests we started already
3518    //     G.tests_finished - number of tests completed (good or bad)
3519    //     G.retry_max     - maximum number of retries
3520    //     G.start_time    - time test started
3521    //     G.retry_until   - the point we stop running new tests
3522    // pct1 : percent done based on number of tests ran
3523    var sofar, outof;
3524
3525    sofar = G.tests_finished;
3526    outof = G.queue.length + G.dequeued.length;
3527
3528    jQuery(".pb1_text").html(" " + sofar + "/" + outof + " " + "tests run");
3529    if (sofar === outof) {
3530        jQuery("#progress_bar").hide();
3531        jQuery("#progress_bar").html("");
3532    }
3533
3534};
3535
3536GIGO.send_survey_global = function (tokens) {
3537  // Only if we are in transparent mode..
3538  if (MirrorConfig.orig_options) {
3539    if (MirrorConfig.options.survey !== MirrorConfig.orig_options.survey  ||
3540     MirrorConfig.options.userdata !== MirrorConfig.orig_options.userdata ) {
3541        MirrorConfig.options.survey = MirrorConfig.orig_options.survey;
3542        MirrorConfig.options.userdata =  MirrorConfig.orig_options.userdata;
3543        GIGO.send_survey(tokens);
3544     }
3545  }
3546};
3547
3548
3549GIGO.send_survey = function (tokens) {
3550
3551    // Temporary(?): disable survey for "test-ipv6.com"; main.test-ipv6.com is 
3552    // now non-op.
3553    if (GIGO.CheckTransparentDomain(document.location.hostname)) {
3554        return;
3555    }
3556
3557    var url = MirrorConfig.options.survey;
3558    if (!url) {
3559        return;
3560    }
3561
3562    if (MirrorConfig.options.userdata) {
3563        // We're going to completely override "url"
3564        if (GIGO.results.ipv4.ip) {
3565            url = GIGO.protocol + "ipv4." + MirrorConfig.options.userdata + MirrorConfig.options.survey;
3566        } else {
3567            url = GIGO.protocol + "ipv6." + MirrorConfig.options.userdata + MirrorConfig.options.survey;
3568        }
3569    }
3570
3571
3572    if (GIGO.is_replay()) {
3573       return;
3574    }
3575
3576    if (GIGO.override) {
3577        jQuery("#survey").html("(Survey posting skipped; test was rigged)");
3578        return;
3579    }
3580
3581
3582    tokens = tokens.join(",");
3583    url += "?x&" + GIGO.cgistats("a") + GIGO.cgistats("aaaa") + GIGO.cgistats("ds4") + GIGO.cgistats("ds6")  + GIGO.cgistats("v6ns") + GIGO.cgistats("dsmtu") + GIGO.cgistats("v6mtu") + "&tokens=" + encodeURI(tokens) + "&rand=" + Math.floor(Math.random() * 2000000000);
3584
3585    if (MirrorConfig.options.survey_ip) {
3586        if (GIGO.results.ipv4.ip) {
3587            url += "&ip4="+GIGO.results.ipv4.ip;
3588        } else {
3589            url += "&ip4=";
3590        }
3591        if (GIGO.results.ipv6.ip) {
3592            url += "&ip6="+GIGO.results.ipv6.ip;
3593        } else {
3594            url += "&ip6=";
3595        }
3596    } else {
3597        if (GIGO.results.ipv4.ip) {
3598            url += "&ip4=a29";
3599        } else {
3600            url += "&ip4=";
3601        }
3602
3603        if (GIGO.results.ipv6.ip) {
3604            url += "&ip6=a29";
3605        } else {
3606            url += "&ip6=";
3607        }
3608    }
3609    url += "&load=" + encodeURI(MirrorConfig.load.domain);
3610
3611
3612    url += "&ip6subtype=" + encodeURI(GIGO.results.ipv6.subtype);
3613    url += "&callback=?";
3614
3615
3616    jQuery("#survey").html("(Updating server side IPv6 readiness stats)");
3617
3618
3619    jQuery.jsonp({
3620        "url": url,
3621        "cache": true,
3622        "pageCache": false,
3623        "timeout": GIGO.max_time,
3624
3625        "success": function (stuff) {
3626            jQuery("#survey").html("(Updated server side IPv6 readiness stats)");
3627        },
3628        "error": function (d, msg) {
3629            jQuery("#survey").html("(Survey posting failed; the above information is accurate, but not recorded.)" + " " + url);
3630        }
3631    });
3632
3633};
3634
3635GIGO.gen_help_link = function (token) {
3636    var page, title, code;
3637    // GIGO.gettext_messages.messages_popups has the urls and translated titles
3638    code = "";
3639    if (GIGO.messages_popups.hasOwnProperty(token)) {
3640        page = GIGO.messages_popups[token][0];
3641        title = GIGO.messages_popups[token][1];
3642        code = "<a href='"+page+"'  onclick=\"GIGO.help_popup('" + page + "','" + title + "'); return false;\" class=\"help_popup\">" + "[more info]" + "</a>";
3643    }
3644    return code;
3645};
3646
3647GIGO.testing_ipv4 = function () {
3648    var s;
3649    s = String(location.hostname);
3650    return (s.match(/ipv4/i) || s.match(/testv4/i) || s.match(/test-v4/i));
3651};
3652
3653
3654GIGO.show_results = function () {
3655    var tokens_hash, i, table, token_expanded, help, s4, s6, sid4, sid6;
3656
3657
3658
3659    // GIGO.dumpObj(this); // requires popups enabled
3660    // Check for some specific issues; and possibly either show
3661    // extra content panels (already in the HTML)  and/or
3662    // highlight our contact form.
3663    tokens_hash = GIGO.oc(GIGO.results.tokens);
3664    if (tokens_hash.hasOwnProperty("Unliklely")) {
3665        GIGO.contact_wanted = 1;
3666        jQuery("#help_plugins").show(); // Encourage more feedback.
3667    }
3668    if (tokens_hash.hasOwnProperty("confused:ASK")) {
3669        if (MirrorConfig.options.comment) {
3670              GIGO.contact_wanted = 1;
3671              jQuery("#help_plugins").show(); // Encourage more feedback.
3672        }
3673    }
3674    if (tokens_hash.hasOwnProperty("webfilter:dsboth")) {
3675        jQuery("#help_plugins").show(); // Less encouraging of soliciting comments on this one.
3676    }
3677    if (tokens_hash.hasOwnProperty("webfilter:blocked")) {
3678        jQuery("#help_plugins").show(); // Less encouraging of soliciting comments on this one.
3679    }
3680
3681    GIGO.check_versions(); // Check OS, Browser, etc
3682    // Show the results to the user
3683    for (i = 0; i < GIGO.results.tokens_expanded.length; i = i + 1) {
3684        token_expanded = GIGO.results.tokens_expanded[i];
3685        if (token_expanded.text !== "-") {
3686
3687            help = GIGO.gen_help_link(token_expanded.token);
3688            if (help) {
3689                token_expanded.text = token_expanded.text + " " + help;
3690            }
3691
3692            // token_expanded.token
3693            // token_expanded.color
3694            // token_expanded.text
3695
3696            table = GIGO.results_table_wrapper(token_expanded.color, token_expanded.text);
3697            jQuery("#results_eof").before(table);
3698        }
3699    }
3700    console.log("GIGO.results.tokens=%o",GIGO.results.tokens);
3701
3702
3703
3704    // Show summary table.  TODO: Make this even simpler for people.
3705    s4 = " " + GIGO.results.score_transition + "/10";
3706    sid4 = "score" + GIGO.results.score_transition;
3707    s6 = " " + GIGO.results.score_strict + "/10";
3708    sid6 = "score" + GIGO.results.score_strict;
3709
3710    if (GIGO.results.score_transition === -1) {
3711        s4 = "n/a";
3712        sid4 = "score0";
3713    }
3714    if (GIGO.results.score_strict === -1) {
3715        s6 = "n/a";
3716        sid6 = "score0";
3717    }
3718
3719    table = "<div id=\"debugtable\"><table width=100%><tr><th colspan=2>" + "Your readiness score" + "</th></tr>";
3720    if (GIGO.testing_ipv4(GIGO.results.score_transition)) {
3721        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>";
3722    }
3723    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>";
3724    table += "</table></div>";
3725    table += "<div class='next'><p>" + "Click to see" + " <a href=\"#\" class=\"tabbutton_tests\"  onclick='return GIGO.tabnav(\"tests\")'>" + "Test Data" + "</a></p></div>";
3726    jQuery("#results_eof").before(table);
3727
3728
3729    // Update specific fields in above table.
3730    jQuery("[name=score_transition]").val(GIGO.results.score_transition);
3731    jQuery("[name=score_strict]").val(GIGO.results.score_strict);
3732
3733    //
3734    // jQuery("#results_eof").before("<div class=\"small\">" + GIGO.results.tokens.join(",") + "</div>");
3735    //
3736
3737    GIGO.show_faq_link(GIGO.results.tokens);
3738
3739    if ((GIGO.results.score_transition === "?") || (GIGO.results.score_transition > 10) || (GIGO.contact_wanted)) {
3740        // I really want to talk to them.
3741        if (MirrorConfig.options.comment) {
3742          // But not if they are from places with known problems.
3743          // China
3744          if (!GIGO.isUnreliable()) {
3745            GIGO.showform();
3746          }
3747        }
3748    }
3749};
3750
3751GIGO.show_faq_link = function (tokens) {
3752    var html, faqs, page, title, linktext, m;
3753
3754    if (/ipv4_only/.test(tokens)) {
3755      page = "faq_ipv4_only.html";
3756    }
3757    if (/broken/.test(tokens)) {
3758      page = "broken.html";
3759    }
3760
3761console.log("show_faq_link: page=%o",page);
3762
3763    if (page) {
3764        jQuery("#comments_unwanted").hide();
3765        jQuery("#comments_faq").show();
3766
3767        title = "Your FAQ";
3768        linktext = "Frequently Asked Questions";
3769
3770        //        handle = GIGO.help_popup(page, title, 0); // Don't auto-switch to this
3771        html = '<a href="#" onclick="return GIGO.help_popup(\'' + page + '\', \'' + title + '\');">' + linktext + '</a>';
3772
3773
3774        m = jQuery("#comments_faq_link");
3775        m.html(html);
3776
3777    }
3778};
3779
3780
3781
3782
3783GIGO.help_popup = function (file, tabname, popup) {
3784
3785    var o, handle, t, hostname, lfile;
3786    if (popup === undefined) {
3787        popup = 1;
3788    }
3789    o = GIGO.newtab(file, tabname, popup);
3790    handle = "#tab_" + o.handle;
3791
3792    if (popup) {
3793        GIGO.tabnav(o.handle);
3794    }
3795
3796    if (!o.loaded) {
3797        o.loaded = 1;
3798
3799        // Because we are doing bad things with base hrefs, we must
3800        // force the help popups to show the original, user-entered
3801        // hostname (instead of the 'current server');  This is to
3802        // avoid cross-domain problems.
3803        file = GIGO.protocol  + String(document.location.hostname) + "/" + file;
3804        lfile = file + '.en_US';
3805
3806
3807        jQuery(handle).html("loading..."); // Loading indicator.
3808        jQuery(handle).load(lfile + " #content", function (responseText, textStatus) {
3809            if (textStatus !== 'success') {
3810                jQuery(handle).html("failed to load" + " " + lfile);
3811            }
3812            t = "<p>";
3813            t = t + "<a href='#' onclick='return GIGO.goback()' class='goback'>";
3814            t = t + "[go back]" + "</a> ";
3815            t = t + "<a target='_blank' href='" + file + "' class='permalink'>";
3816            t = t + "[permalink]" + "</a> ";
3817            t = t + "</p>";
3818
3819            jQuery(handle).append(t);
3820        });
3821        if (!popup) {
3822            jQuery(handle).hide();
3823        }
3824    }
3825    return (o.handle);
3826};
3827
3828/*global GIGO, jQuery, alert, $gt, Browser, navigator */
3829
3830GIGO.fix_version = function (underscored) {
3831    var t;
3832    t = underscored.replace(/_/g, ".");
3833    return t;
3834};
3835
3836GIGO.zeropad = function (version) {
3837    // Take a version number like 4.10 and return back 00004.00010
3838    // Pad any sequence of digits to 10 points
3839    // So, for every matching set of \d+
3840    // create new string
3841    // replace \b(original string)\b with new string
3842    var smallnumber, mymatch, mymatched, myindex, newstring, replace_re;
3843
3844    smallnumber = /\b(\d{1,9})\b/;
3845    while (smallnumber.test(version)) {
3846        mymatch = smallnumber.exec(version);
3847        mymatched = mymatch[0];
3848        myindex = mymatch.index;
3849
3850        newstring = mymatched;
3851        while (newstring.length < 10) {
3852            newstring = "0" + newstring;
3853        }
3854        replace_re = new RegExp("\\b" + mymatched + "\\b");
3855        version = version.replace(replace_re, newstring);
3856    }
3857    return version;
3858};
3859
3860GIGO.check_version = function (appname, current, suggested) {
3861    var t, table, current_compare, suggested_compare;
3862    // Convert 10_6_7 to 10.6.7 before doing comparisons.
3863    if (current) {
3864        current = current.toString();
3865        current = current.replace(/_/g, ".");
3866        suggested = suggested.replace(/_/g, ".");
3867
3868        current_compare = GIGO.zeropad(current);
3869        suggested_compare = GIGO.zeropad(suggested);
3870
3871        if (current_compare < suggested_compare) {
3872            t = "%app: You are running version %found; we recommend %suggest or newer.";
3873            t = t.replace(/%app/, appname);
3874            t = t.replace(/%found/, current);
3875            t = t.replace(/%suggest/, suggested);
3876            table = GIGO.results_table_wrapper("orange", t);
3877            jQuery("#results_eof").before(table);
3878        }
3879    }
3880};
3881
3882GIGO.check_mac_os_version = function () {
3883    // Firefox will only return "10.6" not "10.6.7".
3884    // Safari and Chrome appear to do the right thing.
3885    if (navigator.userAgent.search(/(FireX|SilkX)/) < 0) {
3886        if (navigator.userAgent.search(/Intel Mac OS X ([0123456789]+[._][0123456789]+[._][0123456789]+)/) >= 0) {
3887            if (RegExp.$1) {
3888                GIGO.check_version("Mac OS X", RegExp.$1, "10.6.7");
3889            }
3890        } else if (navigator.userAgent.search(/Intel Mac OS X ([0123456789]+[._][0123456789]+)/) >= 0) {
3891            if (RegExp.$1) {
3892                GIGO.check_version("Mac OS X", RegExp.$1, "10.6.7");
3893            }
3894        }
3895    }
3896};
3897
3898
3899
3900GIGO.check_browser_firefox = function () {
3901    if (Browser.firefox) {
3902        // Firefox only reports "4.0" not "4.0.1"
3903        if (Browser.Platform.mac) {
3904            GIGO.check_version("Firefox", Browser.version, "14");
3905        }
3906    }
3907};
3908
3909GIGO.check_browser_safari = function () {
3910    if (Browser.safari) {
3911        GIGO.check_version("Safari", Browser.version, "5.0.5");
3912    }
3913};
3914
3915GIGO.check_browser_opera = function () {
3916    if (Browser.opera) {
3917        // Browser.version for opera reports "11.1" not "11.10"
3918        if (navigator.userAgent.search(/Version\/([0-9.]+)$/) >= 0) {
3919            if (RegExp.$1) {
3920                GIGO.check_version("Opera", RegExp.$1, "11.10");
3921            }
3922        }
3923    }
3924};
3925
3926
3927GIGO.check_versions = function () {
3928    GIGO.check_mac_os_version();
3929    GIGO.check_browser_firefox();
3930    GIGO.check_browser_opera();
3931};
3932
3933/*global GIGO, jQuery, alert */
3934/*jslint browser: true */
3935/*jslint regexp: true */
3936
3937GIGO.goback = function () {
3938    var prev;
3939
3940    // Remove the latest window from history.
3941    if (GIGO.tabhistory.length > 0) {
3942        GIGO.tabhistory.pop();
3943    }
3944
3945    // Try and go to the window before that.
3946    if (GIGO.tabhistory.length > 0) {
3947        prev = GIGO.tabhistory.pop();
3948        GIGO.tabnav(prev);
3949    }
3950    return false;
3951};
3952
3953GIGO.extra_tabs = {};
3954GIGO.newtab = function (which, title) {
3955    // INPUT:  name of document or handle
3956    // INPUT:  title to give tab
3957    // OUTPUT: object.   object.handle = the name we should use.
3958    //          can be altered later by other functions.
3959    //  If the handle already exists, no new tab is created.
3960    //  New tab is NOT made the foreground tab - use GIGO.tabnav
3961    var w, html, m;
3962
3963
3964    if (GIGO.extra_tabs.hasOwnProperty(which)) {
3965        return GIGO.extra_tabs[which];
3966    }
3967
3968
3969    w = which.replace(/[^a-z0-9]/g, "_");
3970    GIGO.extra_tabs[which] = {
3971        "original": which,
3972        "handle": w,
3973        "title": title
3974    };
3975
3976    html = '<li><a href="#" class="tabbutton_' + w + '" onclick="return GIGO.tabnav(\'' + w + '\');">' + title + '</a></li>';
3977    m = jQuery("ul#tabnavlist");
3978    m.append(html);
3979
3980    //html = '<div id="tab_' + w + ' style="display:none"></div>';
3981    html = '<div id="tab_' + w + '" ></div>';
3982
3983    m = jQuery("div#tabbox_inside");
3984    m.append(html);
3985
3986
3987    return (GIGO.extra_tabs[which]);
3988
3989};
3990
3991GIGO.tabnav = function (which) {
3992    // "which" is which tab to show.
3993    var prev, i, m;
3994    prev = "";
3995
3996    // Find out what the previous window was
3997    if (GIGO.tabhistory.length > 0) {
3998        prev = GIGO.tabhistory.pop();
3999        GIGO.tabhistory.push(prev);
4000    }
4001    // Update the history, only if the previous window was different
4002    if (prev !== which) {
4003        GIGO.tabhistory.push(which);
4004    }
4005
4006    // Hide everything.
4007    jQuery("#tab_main").hide();
4008    jQuery("#tab_tests").hide();
4009    jQuery("#tab_tech").hide();
4010    jQuery("#tab_stats").hide();
4011    jQuery("#tab_helpdesk").hide();
4012    jQuery("#tab_mail").hide();
4013    jQuery("#tab_debug").hide();
4014    jQuery("#tab_faq").hide();
4015    jQuery("#tab_popup").hide();
4016    jQuery("#tab_sites").hide();
4017
4018
4019    // Remove any highlight attributes on tabs.
4020    jQuery("a.tabbutton_main").removeAttr("id");
4021    jQuery("a.tabbutton_tests").removeAttr("id");
4022    jQuery("a.tabbutton_tech").removeAttr("id");
4023    jQuery("a.tabbutton_stats").removeAttr("id");
4024    jQuery("a.tabbutton_helpdesk").removeAttr("id");
4025    jQuery("a.tabbutton_mail").removeAttr("id");
4026    jQuery("a.tabbutton_debug").removeAttr("id");
4027    jQuery("a.tabbutton_faq").removeAttr("id");
4028    jQuery("a.tabbutton_popup").removeAttr("id");
4029    jQuery("a.tabbutton_sites").removeAttr("id");
4030
4031
4032    // Same thing for all the extra tabs.  TODO: Merge the above into just GIGO.extra_tabs or GIGO.tabs    
4033    for (i in GIGO.extra_tabs) {
4034        if (GIGO.extra_tabs.hasOwnProperty(i)) {
4035
4036            m = jQuery("#tab_" + GIGO.extra_tabs[i].handle);
4037            m.hide();
4038
4039            m = jQuery("a.tabbutton_" + GIGO.extra_tabs[i].handle);
4040            m.removeAttr("id");
4041        }
4042    }
4043
4044
4045    // Re-highlight and show the desirable tab.
4046    jQuery("#tab_" + which).show();
4047    jQuery("a.tabbutton_" + which).attr("id", "tabcurrent");
4048
4049    // Possibly, really make the contact tab button stand out.
4050    if (GIGO.contact_wanted) {
4051        jQuery("a.tabbutton_mail").attr("id", "contactme");
4052    }
4053
4054    return false;
4055
4056};
4057
4058GIGO.tabnav_tests = function (which) {
4059    // Change detail of "tests" page
4060    GIGO.tabnav("tests");
4061    jQuery("#tab_tests_simple").hide();
4062    jQuery("#tab_tests_tech").hide();
4063    jQuery("#tab_tests_" + which).show();
4064    return false;
4065};
4066
4067/*global GIGO */
4068/*jslint maxlen: 100 */
4069/* Stop bothering me about long lines */
4070/*jslint sub: true */
4071/* Stop bothering me about   "foo"] */
4072
4073// Scores:
4074//   #1: Readiness for content providers to go IPv6
4075//   #2: Readiness for content providers to give up IPv4
4076
4077// GREEN = success, green block with check mark
4078// RED = big caution symbol, red block
4079// BLUE = info symbol, blue block
4080// ORANGE = ? symbol
4081
4082// TEXT is now in source/text/text.en-us  and similiar; to be compiled in at build time.
4083GIGO.scores = {
4084    "No Direct IP": [10, 10, "ORANGE"],
4085    "No Direct IPv4": [9, 10, "BLUE"],
4086    "No Direct IPv6": [10, 10, "BLUE"],
4087    "tls_warning": [10, 10, "BLUE"],
4088    "tls_beta": [10, 10, "BLUE"],
4089    "tls_available": [10, 10, "BLUE"],
4090    "6to4": [7, 7, "BLUE"],
4091    "teredo": [7, 7, "BLUE"],
4092    "teredo-v4pref": [10, 7, "BLUE"],
4093    "teredo-minimum": [10, 0, "BLUE"],
4094    "IPv6 MTU": [1, 1, "RED"],
4095    "confused:ASK": [0, 0, "ORANGE"],
4096    "confused:NOASK": [0, 0, "ORANGE"],
4097    "dualstack:ipv4_preferred": [10, 10, "GREEN"],
4098    "dualstack:ipv6_preferred": [10, 10, "GREEN"],
4099    "dualstack:slow": [7, 7, "BLUE"],
4100    "ipv4_only": [10, 0, "BLUE"],
4101    "ipv4_only:ds_good": [10, 0, "BLUE"],
4102    "ipv4_only:ds_slow": [5, 0, "RED"],
4103    "ipv4_only:ds_timeout": [5, 0, "RED"],
4104    "ipv4_slow": [5, 10, "RED"],
4105    "ipv6_only": [0, 10, "BLUE"],
4106    "ipv6_slow": [10, 5, "RED"],
4107    "ipv6_timeout": [10, 0, "RED"],
4108    "ipv6:nodns": [10, 0, "RED"],
4109    "broken_ipv6": [0, 0, "RED"],
4110    "webfilter:blocked": [-1, -1, "ORANGE"],
4111    "webfilter:dsboth": [10, 10, "ORANGE"],
4112    "webfilter:addons": [10, 10, "ORANGE"],
4113    "webfilter:firefox": [10, 10, "ORANGE"],
4114    "v6ns:ok": [10, 10, "GREEN"],
4115    "v6ns:bad": [10, 9, "BLUE"],
4116    "ip_timeout:firefox": [10, 10, "RED"],
4117    "confused:obbo": [10, 9, "BLUE"],
4118    "apple:dnsbug_aaaa": [10, 7, "BLUE"],
4119    "apple:dnsbug_ds": [10, 7, "BLUE"],
4120    "ipv4:no_address": [10, 10, "BLUE"],
4121    "ipv6:no_address": [10, 10, "RED"],
4122    "no_address": [10, 10, "RED"],
4123    "opera": [10, 10, "ORANGE"],
4124    "opera:turbo": [0, 0, "RED"],
4125    "dualstack:safe": [10, 10, "GREEN"],
4126    "needs_ipv6": [10, 10, "BLUE"],
4127    "dualstack:unsafe": [10, 10, "RED"],
4128    "dualstack:mtu": [10, 10, "RED"],
4129    "tunnel_dumb": [10, 10, "ORANGE"],
4130    "he_tunnel_dumb": [10, 10, "BLUE"],
4131    "tunnel_6rd_dumb": [10, 10, "BLUE"],
4132    "proxy_via": [10, 10, "ORANGE"],
4133    "proxy_via_dumb": [10, 10, "ORANGE"],
4134    "broken": [0, 0, "BLUE"],
4135    "avoids_ipv6": [10, 10, "ORANGE"],
4136    "ood": [10, 10, "RED"]
4137};
4138
4139/*global GIGO, MirrorConfig, jQuery, alert, $gt */
4140/*jslint nomen: true */
4141
4142GIGO.form_setup_value = function (r) {
4143    var s;
4144    s = r.status + "," + r.time_ms / 1000.0;
4145
4146    if (r.ipinfo) {
4147        if (r.ipinfo.via) {
4148            s = s + " " + r.ipinfo.via;
4149        }
4150    }
4151    return s;
4152};
4153
4154
4155GIGO.form_setup = function (tokens) {
4156    tokens = tokens.join(",");
4157    jQuery("[name=a]").val(GIGO.form_setup_value(GIGO.results.tests.test_a));
4158    jQuery("[name=aaaa]").val(GIGO.form_setup_value(GIGO.results.tests.test_aaaa));
4159    jQuery("[name=ds4]").val(GIGO.form_setup_value(GIGO.results.tests.test_ds4));
4160    jQuery("[name=ds6]").val(GIGO.form_setup_value(GIGO.results.tests.test_ds6));
4161    jQuery("[name=v6mtu]").val(GIGO.form_setup_value(GIGO.results.tests.test_v6mtu));
4162    jQuery("[name=v6ns]").val(GIGO.form_setup_value(GIGO.results.tests.test_v6ns));
4163    jQuery("[name=dsmtu]").val(GIGO.form_setup_value(GIGO.results.tests.test_dsmtu));
4164    jQuery("[name=ip4]").val(GIGO.results.ipv4.ip);
4165    jQuery("[name=ip6]").val(GIGO.results.ipv6.ip);
4166    jQuery("[name=ip6subtype]").val(GIGO.results.ipv6.subtype);
4167    jQuery("[name=tokens]").val(tokens);
4168
4169    jQuery("[name=subdomain]").val(GIGO.mirrorconfig("site", "name"));
4170
4171    jQuery(".progress_bar").remove();
4172
4173    jQuery("[name=form_tab_main]").val(jQuery("#tab_main_inside")[0].outerHTML);
4174    jQuery("[name=form_config]").val(JSON.encode(MirrorConfig));
4175    jQuery("[name=form_results]").val(JSON.encode(GIGO.results));
4176    jQuery("[name=form_replay]").val(GIGO.generate_share_link());
4177
4178};
4179
4180
4181GIGO.showform = function () {
4182    var msgs, share_text, share_link;
4183
4184    if (GIGO.isUnreliable()){
4185      return;
4186    }
4187
4188    // Highlight the tab
4189    jQuery("a.tabbutton_mail").attr("id", "contactme");
4190    GIGO.contact_wanted = 1;
4191    jQuery("#comments_wanted").show();
4192    jQuery("#comments_unwanted").hide();
4193
4194    jQuery("#contact_form").show();
4195    jQuery("[name=purpose]").val("bug");
4196
4197    share_text = "share your results";
4198    share_link = "<a href='#' onclick='return GIGO.tabnav(\"mail\");'>%1</a>";
4199    share_link = share_link.replace(/%1/, share_text);
4200
4201    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?";
4202    msgs = msgs.replace(/%share/, share_link);
4203
4204    msgs = "<div><p><span id='highlighter'>" + msgs + "</span></p></div>";
4205
4206    jQuery("#results_eof").before(msgs);
4207
4208    // Add fields to the contact form
4209};
4210
4211
4212GIGO.debuggercomments = function (thisform) {
4213
4214    var s = "[Debug info follows]\n" + GIGO._dumpObj(GIGO.results, ".", " ", 0);
4215
4216    GIGO.showform();
4217    GIGO.tabnav("mail");
4218    // "notes" for top box.  "comments" for bottom box.
4219    jQuery("[name=notes]").val(s);
4220    return false;
4221};
4222
4223
4224GIGO.validate_form = function (thisform) {
4225
4226    check = function (x) {
4227        try {
4228            return  x.value.match(/\S/)
4229        } catch (e) {
4230            return false
4231        }
4232    }
4233
4234    // Nothing filled out?
4235    if (!( check(thisform.notes) || check(thisform.comments) || check(thisform.contact)) ) {
4236        thisform.notes.focus();
4237        return false;
4238    }
4239
4240    if (!( $('#consent').prop('checked'))) {
4241      alert("Please consent to sharing your data.");
4242      thisform.consent.focus();
4243      return false;
4244    }
4245
4246    if ((thisform.contact.value === null) || (thisform.contact.value === "")) {
4247        if (!GIGO.validate_form.asked) {
4248            GIGO.validate_form.asked = 1;
4249            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.");
4250            thisform.contact.focus();
4251            return false;
4252        }
4253
4254    }
4255
4256
4257    return true;
4258};
4259GIGO.validate_form.asked = 0;
4260
4261GIGO.onchange_purpose = function (thisform) {
4262
4263    var e = document.getElementById("purpose");
4264    var strUser = e.options[e.selectedIndex].value;
4265
4266    jQuery("div[id^=response]").hide();
4267    jQuery("#contact_form").hide();
4268    switch (strUser) {
4269        case "isp":
4270            jQuery("#response_isp").show();
4271            break;
4272
4273        case "hacked":
4274        jQuery("#response_hacked").show();
4275            break;
4276
4277        case "gfw":
4278        jQuery("#response_gfw").show();
4279            break;
4280
4281        case "isp":
4282        jQuery("#response_isp").show();
4283            break;
4284
4285        default:
4286        jQuery("#contact_form").show();
4287            break;
4288    };
4289
4290
4291    console.log("this is %o", strUser);
4292};
4293
4294/*global GIGO jQuery */
4295/*jslint browser: true */
4296
4297
4298// Based on these variablse : status_a  status_aaaa  status_ds4  status_ds6
4299// which have values of  ok, slow, bad, timeout  (o,s,b,t)
4300// what is the primary diagnosis of the person's connectivity?
4301// Implemented as a table instead of a giant if/else  (which was not terribly maintainable)
4302// confused:NOASK should ask the user to fill out the form; it will replace ASK with the initials
4303// of the status that was used to consult this table.  From there a human can better
4304// attempt to classify that user's experience.
4305
4306GIGO.sym_primary = {
4307    "bbbb": "webfilter:blocked",
4308    "bbbo": "webfilter:blocked",
4309    "bbbs": "webfilter:blocked",
4310    "bbbt": "webfilter:blocked",
4311    "bbob": "webfilter:blocked",
4312    "bboo": "webfilter:blocked",
4313    "bbos": "webfilter:blocked",
4314    "bbot": "webfilter:blocked",
4315    "bbsb": "webfilter:blocked",
4316    "bbso": "webfilter:blocked",
4317    "bbss": "webfilter:blocked",
4318    "bbst": "webfilter:blocked",
4319    "bbtb": "webfilter:blocked",
4320    "bbto": "webfilter:blocked",
4321    "bbts": "webfilter:blocked",
4322    "bbtt": "webfilter:blocked",
4323    "bobb": "confused:NOASK",
4324    "bobo": "ipv6_only",
4325    "bobs": "ipv6_only",
4326    "bobt": "confused:NOASK",
4327    "boob": "confused:NOASK",
4328    "booo": "ipv6_only,webfilter:addons",
4329    "boos": "webfilter:dsboth",
4330    "boot": "confused:NOASK",
4331    "bosb": "confused:NOASK",
4332    "boso": "webfilter:dsboth",
4333    "boss": "ipv6_only,webfilter:addons",
4334    "bost": "confused:NOASK",
4335    "botb": "confused:NOASK",
4336    "boto": "confused:NOASK",
4337    "bots": "confused:NOASK",
4338    "bott": "confused:NOASK",
4339    "bsbb": "confused:NOASK",
4340    "bsbo": "ipv6_only",
4341    "bsbs": "ipv6_only",
4342    "bsbt": "confused:NOASK",
4343    "bsob": "confused:NOASK",
4344    "bsoo": "ipv6_only,ipv6_slow,webfilter:addons",
4345    "bsos": "webfilter:dsboth",
4346    "bsot": "confused:NOASK",
4347    "bssb": "confused:NOASK",
4348    "bsso": "webfilter:dsboth",
4349    "bsss": "ipv6_only,ipv6_slow,webfilter:addons",
4350    "bsst": "confused:NOASK",
4351    "bstb": "confused:NOASK",
4352    "bsto": "confused:NOASK",
4353    "bsts": "confused:NOASK",
4354    "bstt": "confused:NOASK",
4355    "btbb": "webfilter:blocked",
4356    "btbo": "webfilter:blocked",
4357    "btbs": "webfilter:blocked",
4358    "btbt": "webfilter:blocked",
4359    "btob": "webfilter:blocked",
4360    "btoo": "webfilter:blocked",
4361    "btos": "webfilter:blocked",
4362    "btot": "webfilter:blocked",
4363    "btsb": "webfilter:blocked",
4364    "btso": "webfilter:blocked",
4365    "btss": "webfilter:blocked",
4366    "btst": "webfilter:blocked",
4367    "bttb": "webfilter:blocked",
4368    "btto": "webfilter:blocked",
4369    "btts": "webfilter:blocked",
4370    "bttt": "webfilter:blocked",
4371    "obbb": "broken",
4372    "obbo": "confused:obbo",
4373    "obbs": "confused:obbs",
4374    "obbt": "confused:NOASK",
4375    "obob": "ipv4_only",
4376    "oboo": "ipv4_only,webfilter:addons",
4377    "obos": "webfilter:dsboth",
4378    "obot": "confused:NOASK",
4379    "obsb": "ipv4_only:ds_slow",
4380    "obso": "webfilter:dsboth",
4381    "obss": "ipv4_only,webfilter:addons",
4382    "obst": "confused:NOASK",
4383    "obtb": "ipv4_only:ds_timeout",
4384    "obto": "confused:NOASK",
4385    "obts": "confused:NOASK",
4386    "obtt": "broken",
4387    "oobb": "confused:NOASK",
4388    "oobo": "dualstack:ipv6_preferred",
4389    "oobs": "confused:NOASK",
4390    "oobt": "confused:NOASK",
4391    "ooob": "dualstack:ipv4_preferred",
4392    "oooo": "dualstack:safe,webfilter:addons",
4393    "ooos": "webfilter:dsboth",
4394    "ooot": "dualstack:ipv4_preferred",
4395    "oosb": "dualstack:slow",
4396    "ooso": "webfilter:dsboth",
4397    "ooss": "dualstack:safe,webfilter:addons",
4398    "oost": "confused:NOASK",
4399    "ootb": "confused:NOASK",
4400    "ooto": "dualstack:ipv6_preferred",
4401    "oots": "confused:NOASK",
4402    "oott": "confused:NOASK",
4403    "osbb": "confused:NOASK",
4404    "osbo": "confused:NOASK",
4405    "osbs": "confused:NOASK",
4406    "osbt": "confused:NOASK",
4407    "osob": "dualstack:ipv4_preferred,ipv6_slow",
4408    "osoo": "dualstack:ipv4_prefered,webfilter:addons",
4409    "osos": "webfilter:dsboth",
4410    "osot": "confused:NOASK",
4411    "ossb": "dualstack:ipv4_preferred,ipv6_slow",
4412    "osso": "webfilter:dsboth",
4413    "osss": "dualstack:ipv4_prefered,webfilter:addons",
4414    "osst": "confused:NOASK",
4415    "ostb": "confused:NOASK",
4416    "osto": "confused:NOASK",
4417    "osts": "confused:NOASK",
4418    "ostt": "confused:NOASK",
4419    "otbb": "broken",
4420    "otbo": "confused:NOASK",
4421    "otbs": "confused:NOASK",
4422    "otbt": "broken",
4423    "otob": "ipv4_only:ds_good,ipv6_timeout",
4424    "otoo": "ipv4_only,webfilter:addons",
4425    "otos": "webfilter:dsboth",
4426    "otot": "confused:NOASK",
4427    "otsb": "ipv4_only:ds_slow,ipv6_timeout",
4428    "otso": "webfilter:dsboth",
4429    "otss": "ipv4_only,webfilter:addons",
4430    "otst": "confused:NOASK",
4431    "ottb": "broken",
4432    "otto": "confused:NOASK",
4433    "otts": "confused:NOASK",
4434    "ottt": "broken", // symptoms.js will overrule this
4435    "sbbb": "confused:NOASK",
4436    "sbbo": "confused:NOASK",
4437    "sbbs": "confused:NOASK",
4438    "sbbt": "confused:NOASK",
4439    "sbob": "ipv4_only,ipv4_slow",
4440    "sboo": "ipv4_only,webfilter:addons",
4441    "sbos": "webfilter:dsboth",
4442    "sbot": "confused:NOASK",
4443    "sbsb": "ipv4_only,ipv4_slow",
4444    "sbso": "webfilter:dsboth",
4445    "sbss": "ipv4_only,webfilter:addons",
4446    "sbst": "confused:NOASK",
4447    "sbtb": "confused:NOASK",
4448    "sbto": "confused:NOASK",
4449    "sbts": "confused:NOASK",
4450    "sbtt": "confused:NOASK",
4451    "sobb": "dualstack:ipv4_preferred,ipv4_slow",
4452    "sobo": "confused:NOASK",
4453    "sobs": "confused:NOASK",
4454    "sobt": "confused:NOASK",
4455    "soob": "dualstack:ipv4_preferred,ipv4_slow",
4456    "sooo": "dualstack_ipv6_preferred,ipv4_slow,webfilter:addons",
4457    "soos": "webfilter:dsboth",
4458    "soot": "confused:NOASK",
4459    "sosb": "dualstack:ipv4_preferred,ipv4_slow",
4460    "soso": "webfilter:dsboth",
4461    "soss": "dualstack_ipv6_preferred,ipv4_slow,webfilter:addons",
4462    "sost": "confused:NOASK",
4463    "sotb": "confused:NOASK",
4464    "soto": "confused:NOASK",
4465    "sots": "confused:NOASK",
4466    "sott": "confused:NOASK",
4467    "ssbb": "confused:NOASK",
4468    "ssbo": "confused:NOASK",
4469    "ssbs": "confused:NOASK",
4470    "ssbt": "confused:NOASK",
4471    "ssob": "confused:NOASK",
4472    "ssoo": "dualstack,ipv4_slow,ipv6_slow,webfilter:addons",
4473    "ssos": "webfilter:dsboth",
4474    "ssot": "confused:NOASK",
4475    "sssb": "dualstack:ipv4_preferred,ipv4_slow,ipv6_slow",
4476    "ssso": "webfilter:dsboth",
4477    "ssss": "dualstack,ipv4_slow,ipv6_slow,webfilter:addons",
4478    "ssst": "confused:NOASK",
4479    "sstb": "confused:NOASK",
4480    "ssto": "confused:NOASK",
4481    "ssts": "confused:NOASK",
4482    "sstt": "confused:NOASK",
4483    "stbb": "confused:NOASK",
4484    "stbo": "confused:NOASK",
4485    "stbs": "confused:NOASK",
4486    "stbt": "confused:NOASK",
4487    "stob": "ipv4_only:ds_good,ipv6_timeout",
4488    "stoo": "ipv4_only:ds_good,webfilter:addons",
4489    "stos": "webfilter:dsboth",
4490    "stot": "confused:NOASK",
4491    "stsb": "ipv4_only:ds_slow,ipv6_timeout",
4492    "stso": "webfilter:dsboth",
4493    "stss": "ipv4_only:ds_good,webfilter:addons",
4494    "stst": "confused:NOASK",
4495    "sttb": "confused:NOASK",
4496    "stto": "confused:NOASK",
4497    "stts": "confused:NOASK",
4498    "sttt": "confused:NOASK",
4499    "tbbb": "webfilter:blocked",
4500    "tbbo": "webfilter:blocked",
4501    "tbbs": "webfilter:blocked",
4502    "tbbt": "webfilter:blocked",
4503    "tbob": "webfilter:blocked",
4504    "tboo": "webfilter:blocked",
4505    "tbos": "webfilter:blocked",
4506    "tbot": "webfilter:blocked",
4507    "tbsb": "webfilter:blocked",
4508    "tbso": "webfilter:blocked",
4509    "tbss": "webfilter:blocked",
4510    "tbst": "webfilter:blocked",
4511    "tbtb": "webfilter:blocked",
4512    "tbto": "webfilter:blocked",
4513    "tbts": "webfilter:blocked",
4514    "tbtt": "webfilter:blocked",
4515    "tobb": "confused:NOASK",
4516    "tobo": "ipv6_only",
4517    "tobs": "confused:NOASK",
4518    "tobt": "confused:NOASK",
4519    "toob": "confused:NOASK",
4520    "tooo": "ipv6_only,webfilter:both",
4521    "toos": "webfilter:dsboth",
4522    "toot": "confused:NOASK",
4523    "tosb": "confused:NOASK",
4524    "toso": "webfilter:dsboth",
4525    "toss": "ipv6_only,webfilter:both",
4526    "tost": "confused:NOASK",
4527    "totb": "confused:NOASK",
4528    "toto": "confused:NOASK",
4529    "tots": "confused:NOASK",
4530    "tott": "confused:NOASK",
4531    "tsbb": "confused:NOASK",
4532    "tsbo": "confused:NOASK",
4533    "tsbs": "confused:NOASK",
4534    "tsbt": "confused:NOASK",
4535    "tsob": "confused:NOASK",
4536    "tsoo": "ipv6_only,webfilter:addons",
4537    "tsos": "webfilter:dsboth",
4538    "tsot": "confused:NOASK",
4539    "tssb": "confused:NOASK",
4540    "tsso": "webfilter:dsboth",
4541    "tsss": "ipv6_only,webfilter:addons",
4542    "tsst": "confused:NOASK",
4543    "tstb": "confused:NOASK",
4544    "tsto": "confused:NOASK",
4545    "tsts": "confused:NOASK",
4546    "tstt": "confused:NOASK",
4547    "ttbb": "webfilter:blocked",
4548    "ttbo": "webfilter:blocked",
4549    "ttbs": "webfilter:blocked",
4550    "ttbt": "webfilter:blocked",
4551    "ttob": "webfilter:blocked",
4552    "ttoo": "webfilter:blocked",
4553    "ttos": "webfilter:blocked",
4554    "ttot": "webfilter:blocked",
4555    "ttsb": "webfilter:blocked",
4556    "ttso": "webfilter:blocked",
4557    "ttss": "webfilter:blocked",
4558    "ttst": "webfilter:blocked",
4559    "tttb": "webfilter:blocked",
4560    "ttto": "webfilter:blocked",
4561    "ttts": "webfilter:blocked",
4562    "tttt": "webfilter:blocked"
4563};
4564
4565/*global GIGO jQuery */
4566/*jslint browser: true */
4567
4568// IPv4 by DNSS   (values: ok or bad)
4569// IPV6 by DNS, and IPV6 type (global, 6[6to4], t[teredo],a[asn]
4570
4571GIGO.sym_helpdesk = {
4572  //   +------ IPv4 by DNS (good,bad)
4573  //   |:+--- IPv6 by DNS (good,bad)
4574  //   |:|+-- IPv6 by IP6 TYPE (global, bad, teredo, 6to4, asn)
4575  //   |:||
4576  'g:gg': "Dual Stack",
4577  'g:gt': "IPv4 plus Teredo",
4578  'g:g6': "6to4",
4579  'g:ga': "Dual Stack, Possible Tunnel",
4580  'g:bg': "Dual Stack - but no Quad-A's (AAAA's)",
4581  'g:bb': "IPv4 Only",
4582  'g:bt': "IPv4 Only (Teredo Detected)",
4583  'g:b6': null,
4584  'g:ba': null,
4585  'g:tb': "IPv4, plus Broken IPv6",
4586  'b:gg': "IPv6 Only",
4587  'b:gt': null,
4588  'b:g6': null,
4589  'b:ga': null,
4590  'b:bg': null,
4591  'b:bb': null,
4592  'b:bt': null,
4593  'b:b6': null,
4594  'b:ba': null,
4595  'b:tb': null,
4596
4597};
4598
4599GIGO.sym_helpdesk_qcode = {
4600  null: null,
4601  "Dual Stack": "46",
4602  "6to4": "624",
4603  "IPv4 Only": "4",
4604  "IPv4 Only (Teredo Detected)": "4",
4605  "IPv4, plus Broken IPv6": "112",
4606  "IPv6 Only": 6
4607
4608  // NO LONGER DETECTED:  With HTTPS, we can't detect these things.
4609  // We're now seeing browsers forcing HTTPS.  We're also seeing
4610  // the use of different ASNs for IPv6 vs IPv4.
4611  //
4612  // "IPv4 plus Teredo": "4t",
4613  // "Dual Stack, Possible Tunnel": "46t",
4614  // "NAT64": "64",
4615  // "NAT64, Possible Tunnel": "64t",
4616
4617};
4618
4619// Input: an array.  Returns: a "hash" (as best as javascript allows).
4620/*global GIGO, jQuery, alert, Browser, $gt */
4621/*jslint browser: true */
4622
4623
4624GIGO.oc = function (a) {
4625    var o, i;
4626    o = {};
4627    for (i = 0; i < a.length; i = i + 1) {
4628        o[a[i]] = '';
4629    }
4630    return o;
4631};
4632
4633GIGO.isdef = function (x) {
4634    return (typeof x !== "undefined");
4635};
4636
4637
4638GIGO.cgistats = function (name) {
4639    var s, status, time_ms, id;
4640    id = "test_" + name;
4641    status = GIGO.results.tests[id].status;
4642    time_ms = GIGO.results.tests[id].time_ms;
4643    s = "&" + name + "=" + status + "," + time_ms;
4644    return s;
4645};
4646
4647
4648
4649GIGO.expand_abbreviation = function (c) {
4650    if (c === "o") {
4651        return "ok";
4652    }
4653    if (c === "b") {
4654        return "bad";
4655    }
4656    if (c === "t") {
4657        return "timeout";
4658    }
4659    if (c === "s") {
4660        return "slow";
4661    }
4662    return "[" + "unknown expansion" + " " + c + "]";
4663};
4664
4665
4666GIGO.check_precheck = function () {
4667    // Dummy function at this time.
4668    // We could decide, based on something we saw, schedule further testing.
4669    return;
4670};
4671
4672GIGO.check_results = function () {
4673
4674    var delta, mini_primary, mini_secondary, tokens, score_transition, score_strict, msgs, i, token, messages_plaintext, token_expanded, tokens_expanded;
4675
4676    tokens_expanded = [];
4677    GIGO.check_precheck();
4678    if (GIGO.queue.length > 0) {
4679        return; // New tasks were added.
4680    }
4681
4682
4683    GIGO.show_debug();
4684    GIGO.repeated = GIGO.repeated + 1;
4685    delta = GIGO.getms() - GIGO.start_time;
4686
4687
4688    // We *could* repeat the tests. This will be sure to get connection times
4689    // versus DNS times.   However, I expect more bandwidth/hits from
4690    // the IPv6 Day announcement; lets try and do this only when it is worth
4691    // bothering.
4692    // In this case, lets do it only if one or more of our tests ran "slow".
4693    if ((GIGO.repeated <= GIGO.retry_min) || ((GIGO.repeated <= GIGO.retry_max) && (GIGO.delta < GIGO.retry_until))) {
4694        if ((GIGO.repeat_only_if_slow === 0) || (GIGO.ministates(["a", "aaaa", "ds4", "ds6",  "v6mtu", "v6ns"]).match(/s/))) {
4695            GIGO.restart_tests(); // Minimum number of retries needed
4696            return;
4697        }
4698    }
4699
4700    GIGO.finished = 1;
4701    GIGO.update_progress(GIGO);
4702    GIGO.fix_comment_form_and_tab(); // Fix up the comments tab
4703
4704
4705    tokens = GIGO.identify_symptoms();
4706    mini_primary = GIGO.ministates(["a", "aaaa", "ds4", "ds6"]);
4707    mini_secondary = GIGO.ministates([ "v6mtu", "v6ns"]);
4708
4709
4710
4711    score_transition = 100;
4712    score_strict = 100;
4713    msgs = ""; // HTML form of messages to give user
4714    messages_plaintext = []; // Array of plaintext in case some one prefers this format
4715    for (i = 0; i < tokens.length; i = i + 1) {
4716        token = tokens[i];
4717
4718
4719        if (GIGO.isdef(GIGO.scores[token])) {
4720            token_expanded = {};
4721            token_expanded.token = token;
4722            token_expanded.score_ipv4 = GIGO.scores[token][0];
4723            token_expanded.score_ipv6 = GIGO.scores[token][1];
4724            token_expanded.color = GIGO.scores[token][2];
4725            token_expanded.text = GIGO.messages[token];
4726            tokens_expanded.push(token_expanded);
4727
4728
4729
4730
4731            if (token_expanded.score_ipv4 <= score_transition) {
4732                score_transition = token_expanded.score_ipv4;
4733            }
4734
4735            if (token_expanded.score_ipv6 <= score_strict) {
4736                score_strict = token_expanded.score_ipv6;
4737            }
4738
4739            msgs = msgs + "<div><p>" + token_expanded.text + "</p></div>";
4740            messages_plaintext.push(token_expanded.text);
4741
4742
4743
4744
4745        } else {
4746            token_expanded = {};
4747            token_expanded.token = token;
4748            token_expanded.color = "YELLOW";
4749            token_expanded.score_ipv4 = 10;
4750            token_expanded.score_ipv6 = 10;
4751            token_expanded.text = "(" + "unknown result code" + ": " + token + ")";
4752            tokens_expanded.push(token_expanded);
4753            msgs = msgs + "<div><p>" + token_expanded.text + "</p></div>";
4754            messages_plaintext.push(token_expanded.text);
4755        }
4756    }
4757
4758
4759    if (GIGO.oc(tokens).hasOwnProperty("confused:ASK")) {
4760        tokens.push("confused:" + mini_primary + ":" + mini_secondary);
4761    }
4762
4763    if (score_transition === 100) {
4764        score_transition = "?";
4765    }
4766    if (score_strict === 100) {
4767        score_strict = "?";
4768    }
4769
4770    if (score_strict > 7) {
4771        GIGO.start_sites(); // Check other sites for connections too.  Starts a new on-page tab.
4772    }
4773    if (score_strict < 9) {
4774        GIGO.update_service_warning(); // China <-> rest of world is unreliable
4775    }
4776
4777    // Copy the results into a place that other people might find them
4778    // particularly if they just use the javascript and not the entire
4779    // test-ipv6.com site code
4780    // GIGO.results = {};
4781
4782    GIGO.results.tokens = tokens;
4783    GIGO.results.score_transition = score_transition;
4784    GIGO.results.score_strict = score_strict;
4785    GIGO.results.divs = msgs;
4786    GIGO.results.messages_plaintext = messages_plaintext;
4787    GIGO.results.debug_code = mini_primary + ":" + mini_secondary;
4788    GIGO.results.tokens_expanded = tokens_expanded;
4789
4790    GIGO.show_debug();
4791    GIGO.finish_helpdesk();
4792
4793
4794    // Callbacks
4795    GIGO.fix_footer_late();
4796
4797    GIGO.send_survey(tokens);
4798    GIGO.send_survey_global(tokens);
4799    GIGO.show_results();
4800    GIGO.form_setup(tokens);
4801    GIGO.show_debug();
4802
4803};
4804
4805GIGO.isUnreliable = function() {
4806  var danger=false;
4807  try {
4808    if (GIGO.unreliable[ GIGO.results.tests.test_asn4.ipinfo.country ]) {
4809      danger=true;
4810    }
4811  } catch (e) {
4812    // noop
4813  }
4814  try {
4815    if (GIGO.unreliable[ GIGO.results.tests.test_asn6.ipinfo.country ]) {
4816      danger=true;
4817    }
4818  } catch (e) {
4819    // noop
4820  }
4821  return danger;
4822};
4823
4824GIGO.update_service_warning = function () {
4825  if (GIGO.isUnreliable()) {
4826    s = "Tests using this web site are unreliable from your location.";
4827    table  = GIGO.results_table_wrapper("orange",s);
4828    jQuery("#results_eof").before(table);
4829  }
4830 };
4831
4832
4833
4834/*global GIGO,  console, Browser */
4835/*jslint browser: true */
4836/* jshint undef: true, unused: true */
4837/* jshint latedef: true */
4838
4839
4840
4841/*jslint regexp: true */
4842
4843/* Map equivalents of ASNs that arent really tunnels or distinct ISPS.
4844   First level: asn4
4845     Second level: asn6
4846        Third level: "1"
4847        */
4848
4849GIGO.asn_same = {
4850    "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],
4851    "surewest": [14051],
4852    "aarnet": [757, 56132],
4853    "tmobile-usa": [21928, 22140],
4854    "att": [7132, 7018, 6389],
4855    "emirates": [8966, 5384],
4856    "sonic": [46375, 7065],
4857    "china-telecom-corp": [4134, 137691]
4858};
4859
4860GIGO.asn_native = {
4861    668: 1, /* DREN, native non-tunnel provider */
4862    24352: 1, /* CERNET2 */
4863    "AR": 1, /* Argentina */
4864    "AW": 1,
4865    "BZ": 1,
4866    "BO": 1,
4867    "BR": 1,
4868    "CL": 1,
4869    "CO": 1,
4870    "CR": 1,
4871    "CU": 1,
4872    "EC": 1,
4873    "GT": 1,
4874    "GY": 1,
4875    "GF": 1,
4876    "HT": 1,
4877    "HN": 1,
4878    "FK": 1,
4879    "MX": 1,
4880    "NI": 1,
4881    "PA": 1,
4882    "PY": 1,
4883    "PE": 1,
4884    "DO": 1,
4885    "MF": 1,
4886    "GS": 1,
4887    "SR": 1,
4888    "TT": 1,
4889    "UY": 1,
4890    "VE": 1
4891};
4892
4893GIGO.unreliable = {
4894  "CN": 1, /* China */
4895};
4896
4897// Exceptions to the unreliable warning.
4898if (window.location.hostname.toLowerCase().endsWith(".cn")) {
4899  GIGO.unreliable["CN"]=0;
4900};
4901
4902
4903GIGO.ministates = function (which) {
4904    var s, i, key, v, tests;
4905
4906    tests = GIGO.results.tests; // Convenience
4907    s = ""; // Build up return value
4908    for (i = 0; i < which.length; i = i + 1) {
4909        key = which[i];
4910        try {
4911            v = GIGO.results.tests["test_" + key].status.charAt(0);
4912            if (GIGO.results.tests["test_" + key].status === "skipped") {
4913              v="x";
4914            }
4915        } catch (e) {
4916            v = "?";
4917        }
4918        s = s + v;
4919    }
4920    return s;
4921};
4922
4923GIGO.find_evidence_of_noscript = function (tests, res) {
4924    var i, key_json, key_img, test_json, test_img, key, keys, blocked;
4925    keys = ["a", "aaaa", "ds", "v6mtu", "v6ns", "dsmtu"];
4926    for (i = 0; i < keys.length; i = i + 1) {
4927        key = keys[i];
4928        key_json = "test_" + key;
4929        key_img = "test_" + key + "_img";
4930        if (tests.hasOwnProperty(key_img)) {
4931            test_json = tests[key_json].status;
4932            test_img = tests[key_img].status;
4933            if (test_img.match(/^[os]/)) {
4934                if (test_json.match(/^[bt]/)) {
4935                    blocked = tests[key_json].url;
4936                    //alert("test " + key + "was blocked by a browser add-on.  Please configure your browser plugins (such as NoScript or AdBlock) to permit " + blocked + " and try this 
4936site again.");
4937                    res.push("webfilter:addons");
4938                    if (Browser.firefox) {
4939                        res.push("webfilter:firefox");
4940                    }
4941                    if (Browser.opera) {
4942                        res.push("opera");
4943                    }
4944                    res.push("webfilter:test_" + key);
4945                    blocked = blocked.replace(/fill=xxxx*/, "fill=xxx...xxx"); // Obscene to show a nearly 2k url
4946                    // Fake the gettext portion.  We need to insert text into that dynamically based on local conditions.
4947                    GIGO.messages["webfilter:test_" + key] = "Your browser blocked" + " " + blocked;
4948
4949                    GIGO.scores["webfilter:test_" + key] = [10, 10, "ORANGE"];
4950
4951                }
4952            }
4953        }
4954    }
4955
4956
4957};
4958
4959GIGO.fallback_to_image_tests = function (tests, res) {
4960    // If the json was bad, but we have an image that worked, fudge it all.
4961    var keys, i, key, key_json, key_img, test_json, test_img;
4962    keys = ["a", "aaaa", "ds", "v6mtu", "v6ns", "dsmtu"];
4963    for (i = 0; i < keys.length; i = i + 1) {
4964        key = keys[i];
4965        key_json = "test_" + key;
4966        key_img = "test_" + key + "_img";
4967        if (tests.hasOwnProperty(key_img)) {
4968
4969            test_json = tests[key_json].status;
4970            test_img = tests[key_img].status;
4971            if (test_img.match(/^[os]/)) {
4972                if (test_json.match(/^[bt]/)) {
4973                    // Copy the IMAGE result data.
4974                    tests["failed_" + key] = tests[key_json];
4975                    tests[key_json] = tests[key_img];
4976                    GIGO.update_status("test_" + key);
4977                    GIGO.update_url("test_" + key);
4978                    GIGO.show_debug();
4979
4980                    if (key === "ds") {
4981                        tests.failed_test_ds4 = tests.test_ds4;
4982                        tests.failed_test_ds6 = tests.test_ds6;
4983                        tests.test_ds4 = tests.test_ds_img;
4984                        tests.test_ds6 = tests.test_ds_img;
4985                        GIGO.update_status("test_ds4");
4986                        GIGO.update_status("test_ds6");
4987                        GIGO.update_url("test_ds4");
4988                        GIGO.update_url("test_ds6");
4989                        GIGO.show_debug();
4990                    }
4991
4992
4993                }
4994            }
4995        }
4996    }
4997
4998
4999};
5000
5001GIGO.dedupe_res = function (res) {
5002    var ret, unique, i;
5003    ret = [];
5004    unique = {};
5005    if (res.length) {
5006        for (i = 0; i < res.length; i = i + 1) {
5007            if (!(unique).hasOwnProperty(res[i])) {
5008                ret.push(res[i]);
5009                unique[res[i]] = 1;
5010            }
5011        }
5012    }
5013    return ret;
5014};
5015
5016
5017GIGO.ipinfo_in_tests = function (tests, name) {
5018    var keys, key, i;
5019    keys = ["a", "aaaa", "ds", "v6mtu", "v6ns", "dsmtu"];
5020    for (i = 0; i < keys.length; i = i + 1) {
5021        key = "test_" + keys[i];
5022        if (tests.hasOwnProperty(key)) {
5023            if (tests[key].hasOwnProperty("ipinfo")) {
5024                if (tests[key].ipinfo.hasOwnProperty(name)) {
5025                    return tests[key].ipinfo[name];
5026                }
5027            }
5028        }
5029    }
5030    return null;
5031};
5032
5033GIGO.check6RD = function (addr4, addr6) {
5034    var i, bytes, addr4Bits, addr6Bits, chunk, index;
5035
5036    // Now process the IPv4 address by generating a string of 32 '0' or '1' based on the host address
5037    bytes = addr4.split('.');
5038    addr4Bits = '';
5039    for (i = 0; i < 4; i = i + 1) {
5040        chunk = parseInt(bytes[i], 10).toString(2);
5041        while (chunk.length < 8)
5042            chunk = '0' + chunk;
5043        addr4Bits = addr4Bits + chunk;
5044    }
5045
5046    // Now process the IPv6 address by generating a string of 64 '0' or '1' based on the /64 prefix
5047    bytes = addr6.split(':');
5048    // We will however skip the first IPv6::/32
5049    addr6Bits = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
5050
5051    // And include instead only the second //32
5052    for (i = 2; i < 4; i = i + 1) {
5053        chunk = parseInt(bytes[i], 16).toString(2);
5054        while (chunk.length < 16)
5055            chunk = '0' + chunk;
5056        addr6Bits = addr6Bits + chunk;
5057    }
5058
5059    // Now check whether full or at least 16 bits of the IPv4 is embedded into the IPv6 prefix
5060    while (addr4Bits.length >= 16) {
5061        index = addr6Bits.indexOf(addr4Bits); // Is part of the IPv4 address embedded in the /64 of IPv6?
5062        if (index >= 0)
5063            return addr4Bits.length + " bits of the IPv4 address are embedded in the IPv6 address starting at " + index;
5064        // Else, remove one leading bit of addr4
5065        addr4Bits = addr4Bits.substr(1, addr4Bits.length - 1);
5066    }
5067    return 0;
5068};
5069
5070GIGO.identify_symptoms = function () {
5071    var  tunnel_6rd, teredo, sixfour, mini_primary, mini_secondary, res, failed_pmtud, x, x_array, tests, via, alist, blist, ia, ib, a4, a6, k, i, r, f4, f6;
5072
5073    res = [];
5074    tests = GIGO.results.tests; // Convenience
5075    GIGO.find_evidence_of_noscript(tests, res);
5076    GIGO.fallback_to_image_tests(tests, res); // Hmm, we might use image connection data instead.
5077
5078    // HTTP proxies?
5079    via = GIGO.ipinfo_in_tests(tests, "via");
5080
5081    // Tunnels?
5082    teredo = (GIGO.results.ipv6.subtype === "Teredo");
5083    sixfour = (GIGO.results.ipv6.subtype === "6to4");
5084    if (GIGO.results.ipv4.ip && GIGO.results.ipv6.ip)
5085        tunnel_6rd = GIGO.check6RD(GIGO.results.ipv4.ip, GIGO.results.ipv6.ip);
5086    else
5087        tunnel_6rd = 0;
5088
5089    GIGO.helpdesk.teredo = teredo; // save for later
5090    GIGO.helpdesk.sixfour = sixfour; // save for later
5091
5092    mini_primary = GIGO.ministates(["a", "aaaa", "ds4", "ds6"]);
5093    mini_secondary = GIGO.ministates([ "v6mtu", "v6ns"]);
5094
5095    mini_ood = GIGO.ministates(["ood"])
5096    console.log("mini_ood %o", mini_ood);
5097    console.log("mini_secondary %o",mini_secondary);
5098
5099    GIGO.helpdesk.mini_primary = mini_primary;
5100    GIGO.helpdesk.mini_secondary = mini_secondary;
5101
5102
5103    // Out of date mirror flagged
5104    if (mini_ood.match(/^[os]/)) {
5105        res.push("ood")
5106    }
5107
5108    //    alert("mini_primary " + mini_primary + " secondary " + mini_secondary);
5109
5110    console.log("res=%o",res);
5111    console.log("mini_primary=%o",mini_primary);
5112
5113    // Convert the JSON table entry to a series of initial elements
5114    x = GIGO.sym_primary[mini_primary];
5115    x_array = x.split(",");
5116
5117    for (i = 0; i < x_array.length; i = i + 1) {
5118        res.push(x_array[i]);
5119    }
5120
5121    console.log("res=%o",res);
5122
5123
5124
5125    // IPv6 Flag Day  - does DUAL STACK choke?
5126    // Only do this, if IPv4 appears to work, or IPv6 appears to work.
5127    // (Otherwise, some Firefox plugin is screwing us again.)
5128    if (tests.test_dsmtu.status === "ok") {
5129        // Do we want to encourage IPv6?  Or acknowledge IPv6?
5130        if (teredo || sixfour || (!GIGO.results.ipv6.ip)) {
5131          // Encourage the use of IPv6
5132          res.push("needs_ipv6");
5133        } else {
5134          // They have IPv6?  Ah, nice.
5135          //res.unshift("dualstack:safe");
5136        }
5137    } else {
5138        res.unshift("dualstack:unsafe");
5139    }
5140
5141
5142
5143    if (via) {
5144        res.unshift("proxy_via_dumb");
5145    }
5146
5147
5148
5149    // Do we have IP addresses?
5150    if ((!GIGO.results.ipv4.ip) && (!GIGO.results.ipv6.ip)) {
5151        res.unshift("no_address");
5152    } else if (!GIGO.results.ipv4.ip) {
5153        res.unshift("ipv4:no_address");
5154    } else if (!GIGO.results.ipv6.ip) {
5155        res.unshift("ipv6:no_address");
5156    }
5157
5158
5159    // IPv4 preferred despite dual stack (and not teredo or fixfour)
5160    if ((!teredo) && (!sixfour)) {
5161        if ((GIGO.results.ipv4.ip) && (GIGO.results.ipv6.ip)) {
5162            if (mini_primary.match(/^[os][os][os][bt]/)) {
5163                res.unshift("avoids_ipv6");
5164            }
5165        }
5166    }
5167
5168    if ((mini_primary.match(/o/)) && (mini_secondary.match(/^t/))) {
5169        // If at least a single name-based lookup worked, but all IP based ones were timeouts
5170        // both IPv4 and IPv6, then we more strongly suspect a filtering plugin.
5171        //  RequestPolicy follows this pattern.
5172        if (Browser && Browser.Engine && Browser.Engine.gecko) {
5173            res.push("ip_timeout:firefox");
5174        }
5175        // Specifically, those were TIMEOUTS
5176    }
5177
5178    // Other transition technologies
5179    if (teredo) {
5180        if (tests.test_aaaa.status === "bad") {
5181            res.push("teredo-minimum");
5182        } else if (mini_primary.match(/^..[os]b/)) {
5183            // a aaaa ds4 ds6
5184            // If IPv4 is preferred, don't penalize the scores so hard.
5185            res.unshift("teredo-v4pref");
5186        } else {
5187            res.push("teredo");
5188        }
5189    }
5190    if (sixfour) {
5191        res.push("6to4");
5192    }
5193
5194
5195    // What about IPv6 only DNS server
5196    if ((tests.test_ds4.status === "ok") || (tests.test_ds4.status === "slow") || (tests.test_ds6.status === "ok") || (tests.test_ds6.status === "slow")) {
5197        if ((tests.test_v6ns.status === "ok") || (tests.test_v6ns.status === "slow")) {
5198            res.push("v6ns:ok");
5199        } else {
5200            res.push("v6ns:bad");
5201        }
5202    }
5203
5204
5205    // Did our larger request work ok?
5206    if (Browser.opera) {
5207        // Opera always fails the 1600 byte test.  WTF?
5208        if ((tests.test_aaaa.status === "ok") && ((tests.test_v6mtu.status === "timeout") || (tests.test_v6mtu.status === "slow"))) {
5209            res.push("IPv6 MTU"); // Uh oh, MTU problems.
5210            failed_pmtud = 1;
5211        }
5212    } else {
5213        if ((tests.test_aaaa.status === "ok") && ((tests.test_v6mtu.status === "bad") || (tests.test_v6mtu.status === "timeout") || (tests.test_v6mtu.status === "slow") || (tests.test_dsmtu.status === "bad") || (tests.test_dsmtu.status === "timeout") || (tests.test_dsmtu.status === "slow"))) {
5214            res.push("IPv6 MTU"); // Uh oh, MTU problems.
5215            failed_pmtud = 1;
5216        }
5217    }
5218    GIGO.helpdesk.failed_pmtud = failed_pmtud;
5219
5220
5221    for (i = 0; i < res.length; i += 1) {
5222
5223        if (failed_pmtud) {
5224            if (res[i] === "dualstack:safe") {
5225                res[i] = "dualstack:mtu";
5226            }
5227            if (res[i] === "dualstack:unsafe") {
5228                res[i] = "dualstack:mtu";
5229            }
5230        }
5231
5232        // Apple DNS bug.  "A" record was fine.
5233        // Dual stack , for some reason, is bad.
5234        if (Browser.Platform.mac || Browser.Platform.ios) {
5235            if (res[i] === 'confused:obbo') {
5236                res[i] = "apple:dnsbug_aaaa"; // Failed to connect to AAAA but dual stack says it shoulda
5237            }
5238            if (res[i].match(/^confused/)) {
5239                if (mini_primary.match(/^obb[sob]/)) {
5240                    res[i] = "apple:dnsbug_aaaa"; // Failed to connect to AAAA but dual stack says it shoulda
5241                }
5242            }
5243        }
5244        if (res[i].match(/^confused/)) {
5245            if ((mini_primary.match(/^ottt/)) && (mini_secondary.match(/^tt/))) {
5246                res[i] = "broken_ipv6";
5247            }
5248        }
5249
5250        console.log("res[i]=%o",res[i]);
5251
5252        if (res[i].match(/^confused/)) {
5253          if (GIGO.isUnreliable()) {
5254            res[i]="confused:NOASK";
5255            console.log("res[i] updated to %o",res[i]);
5256          }
5257        }
5258    }
5259
5260    if (res.length === 0) {
5261        res.push("Unknown");
5262    }
5263    res = GIGO.dedupe_res(res);
5264
5265    console.log("score mini_primary=%o",mini_primary);
5266    console.log("score mini_secondary=%o",mini_secondary);
5267    console.log("score res=%o",res);
5268
5269    return res;
5270
5271};
5272
5273/*global GIGO:true, jQuery,  window,  alert,  Browser */
5274/*jslint browser: true */
5275
5276try {
5277    GIGO.tryme = 1;
5278} catch (e) {
5279    GIGO = {};
5280}
5281
5282GIGO.hide_os_osx = function () {
5283    jQuery(".os_osx").hide(250);
5284};
5285GIGO.hide_os_ios = function () {
5286    jQuery(".os_ios").hide(250);
5287};
5288GIGO.hide_os_other = function () {
5289    jQuery(".os_other").hide(250);
5290};
5291GIGO.hide_os_windows = function () {
5292    jQuery(".os_windows").hide(250);
5293};
5294GIGO.hide_os_linux = function () {
5295    jQuery(".os_linux").hide(250);
5296};
5297
5298GIGO.hide_os_all = function () {
5299    GIGO.hide_os_other();
5300    GIGO.hide_os_osx();
5301    GIGO.hide_os_ios();
5302    GIGO.hide_os_windows();
5303    GIGO.hide_os_linux();
5304};
5305
5306GIGO.show_os_osx = function () {
5307    jQuery(".os_osx").show(250);
5308};
5309GIGO.show_os_ios = function () {
5310    jQuery(".os_ios").show(250);
5311};
5312GIGO.show_os_windows = function () {
5313    jQuery(".os_windows").show(250);
5314};
5315GIGO.show_os_linux = function () {
5316    jQuery(".os_linux").show(250);
5317};
5318GIGO.show_os_other = function () {
5319    jQuery(".os_other").show(250);
5320};
5321
5322GIGO.show_os_all = function () {
5323    GIGO.show_os_other();
5324    GIGO.show_os_osx();
5325    GIGO.show_os_ios();
5326    GIGO.show_os_windows();
5327    GIGO.show_os_linux();
5328};
5329
5330GIGO.show_os_only_osx = function () {
5331    GIGO.hide_os_all();
5332    GIGO.show_os_osx();
5333};
5334GIGO.show_os_only_ios = function () {
5335    GIGO.hide_os_all();
5336    GIGO.show_os_ios();
5337};
5338GIGO.show_os_only_windows = function () {
5339    GIGO.hide_os_all();
5340    GIGO.show_os_windows();
5341};
5342GIGO.show_os_only_linux = function () {
5343    GIGO.hide_os_all();
5344    GIGO.show_os_linux();
5345};
5346
5347GIGO.show_os_start = function () {
5348    if (Browser.Platform.mac) {
5349        GIGO.show_os_only_osx();
5350    } else if (Browser.Platform.windows) {
5351        GIGO.show_os_only_windows();
5352    } else if (Browser.Platform.linux) {
5353        GIGO.show_os_only_linux();
5354    } else if (Browser.Platform.ios) {
5355        GIGO.show_os_only_ios();
5356    } else {
5357        // Be aware we will show ALL platforms we know about.  
5358    }
5359};
5360
5361GIGO.sites_parsed={
5362 "2.ayepv6.com": {
5363  "site": "ayepv6.com",
5364  "mirror": false,
5365  "hide": false,
5366  "v4": "https://v4.test-ipv6.vu.ayepv6.com/images/knob_green.png",
5367  "v6": "https://v6.test-ipv6.vu.ayepv6.com/images/knob_green.png",
5368  "loc": "UK",
5369  "provider": "Stephen Strowes (hosted at Vultr)",
5370  "monitor": "Stephen Strowes \[email protected]\u003e",
5371  "contact": "",
5372  "reason": "",
5373  "transparent": false
5374 },
5375 "8n1.org": {
5376  "site": "8n1.org",
5377  "mirror": false,
5378  "hide": false,
5379  "v4": "https://ip4.8n1.org/test.gif",
5380  "v6": "https://ip6.8n1.org/test.gif",
5381  "loc": "NL",
5382  "provider": "8n1.org - a simple pastebin",
5383  "monitor": "Sander Smeenk \[email protected]\u003e",
5384  "contact": "",
5385  "reason": "",
5386  "transparent": false
5387 },
5388 "ayepv6.com": {
5389  "site": "ayepv6.com",
5390  "mirror": false,
5391  "hide": false,
5392  "v4": "https://v4.test-ipv6.do.ayepv6.com/images/knob_green.png",
5393  "v6": "https://v6.test-ipv6.do.ayepv6.com/images/knob_green.png",
5394  "loc": "UK",
5395  "provider": "Stephen Strowes (hosted at Digital Ocean)",
5396  "monitor": "Stephen Strowes \[email protected]\u003e",
5397  "contact": "",
5398  "reason": "",
5399  "transparent": false
5400 },
5401 "bvconline.com.ar": {
5402  "site": "bvconline.com.ar",
5403  "mirror": false,
5404  "hide": false,
5405  "v4": "http://ipv4.test-ipv6.bvconline.com.ar/knob_green.png",
5406  "v6": "http://ipv6.test-ipv6.bvconline.com.ar/knob_green.png",
5407  "loc": "AR",
5408  "provider": "BVNET S.A",
5409  "monitor": "Ariel Cuesta \[email protected]\u003e",
5410  "contact": "",
5411  "reason": "",
5412  "transparent": false
5413 },
5414 "eurobilltracker.com": {
5415  "site": "eurobilltracker.com",
5416  "mirror": false,
5417  "hide": false,
5418  "v4": "https://ipv4-test-ipv6.eurobilltracker.com/img/1x1.gif",
5419  "v6": "https://ipv6-test-ipv6.eurobilltracker.com/img/1x1.gif",
5420  "loc": "FI",
5421  "provider": "EuroBillTracker",
5422  "monitor": "Anssi Johansson \[email protected]\u003e",
5423  "contact": "",
5424  "reason": "",
5425  "transparent": false
5426 },
5427 "he.net": {
5428  "site": "he.net",
5429  "mirror": false,
5430  "hide": false,
5431  "v4": "https://ipv4.tunnelbroker.net/images/helogo.gif",
5432  "v6": "https://ipv6.tunnelbroker.net/images/helogo.gif",
5433  "loc": "US (CA)",
5434  "provider": "HE.net",
5435  "monitor": "Hurricane Electric \[email protected]\u003e",
5436  "contact": "Mike Tindle \[email protected]\u003e",
5437  "reason": "",
5438  "transparent": false
5439 },
5440 "jamieweb.net": {
5441  "site": "jamieweb.net",
5442  "mirror": false,
5443  "hide": false,
5444  "v4": "https://ipv4.jamieweb.net/ipv4-only.png",
5445  "v6": "https://ipv6.jamieweb.net/ipv6-only.png",
5446  "loc": "UK",
5447  "provider": "Jamie Scaife (JamieWeb)",
5448  "monitor": "Jamie Scaife \[email protected]\u003e",
5449  "contact": "",
5450  "reason": "",
5451  "transparent": false
5452 },
5453 "mudgee.host": {
5454  "site": "mudgee.host",
5455  "mirror": false,
5456  "hide": false,
5457  "v4": "https://ipv4.mudgee.host/logo.png",
5458  "v6": "https://ipv6.mudgee.host/logo.png",
5459  "loc": "AU",
5460  "provider": "Mudgee Host",
5461  "monitor": "Fraser Stuart \[email protected]\u003e",
5462  "contact": "",
5463  "reason": "",
5464  "transparent": false
5465 },
5466 "nic.br": {
5467  "site": "nic.br",
5468  "mirror": false,
5469  "hide": false,
5470  "v4": "https://v4.ipv6.br/img/logo-ipv6.png",
5471  "v6": "https://v6.ipv6.br/img/logo-ipv6.png",
5472  "loc": "BR",
5473  "provider": "NIC.br",
5474  "monitor": "Antonio M. Moreiras \[email protected]\u003e",
5475  "contact": "",
5476  "reason": "",
5477  "transparent": false
5478 },
5479 "nsx.de": {
5480  "site": "nsx.de",
5481  "mirror": false,
5482  "hide": false,
5483  "v4": "https://ipv4.nsx.de/images/knob_valid_green.png",
5484  "v6": "https://ipv6.nsx.de/images/knob_valid_green.png",
5485  "loc": "DE",
5486  "provider": "Stephan Fiebrandt (personal)",
5487  "monitor": "Stephan Fiebrandt \[email protected]\u003e",
5488  "contact": "",
5489  "reason": "",
5490  "transparent": false
5491 },
5492 "salesianimestre.it": {
5493  "site": "salesianimestre.it",
5494  "mirror": false,
5495  "hide": false,
5496  "v4": "https://ipv4.salesianimestre.it/check.png",
5497  "v6": "https://ipv6.salesianimestre.it/check.png",
5498  "loc": "IT",
5499  "provider": "Salesiani Don Bosco Mestre",
5500  "monitor": "Vittore Zen \[email protected]\u003e",
5501  "contact": "",
5502  "reason": "",
5503  "transparent": false
5504 },
5505 "stdio.be": {
5506  "site": "stdio.be",
5507  "mirror": false,
5508  "hide": false,
5509  "v4": "http://ipv4.stdio.be/images/knob_valid_green.png",
5510  "v6": "http://ipv6.stdio.be/images/knob_valid_green.png",
5511  "loc": "DE",
5512  "provider": "Andrew Yourtchenko (personal)",
5513  "monitor": "Andrew Yourtchenko \[email protected]\u003e",
5514  "contact": "",
5515  "reason": "",
5516  "transparent": false
5517 },
5518 "test-ipv6.cgates.lt": {
5519  "site": "test-ipv6.cgates.lt",
5520  "mirror": false,
5521  "hide": false,
5522  "v4": "http://ipv4.test-ipv6.cgates.lt/images-nc/knob_green.png",
5523  "v6": "http://ipv6.test-ipv6.cgates.lt/images-nc/knob_green.png",
5524  "loc": "LT",
5525  "provider": "Cgates",
5526  "monitor": "Marius Sokas \[email protected]\u003e",
5527  "contact": "",
5528  "reason": "",
5529  "transparent": false
5530 },
5531 "www.cidercounty.org.uk": {
5532  "site": "www.cidercounty.org.uk",
5533  "mirror": false,
5534  "hide": false,
5535  "v4": "https://ipv4.cidercounty.org.uk/images/happy_face.gif",
5536  "v6": "https://ipv6.cidercounty.org.uk/images/happy_face.gif",
5537  "loc": "UK",
5538  "provider": "Allen Coates (hosted at A\u0026A)",
5539  "monitor": "Allen Coates \[email protected]\u003e",
5540  "contact": "",
5541  "reason": "",
5542  "transparent": false
5543 },
5544 "www.excathedra.co": {
5545  "site": "www.excathedra.co",
5546  "mirror": false,
5547  "hide": false,
5548  "v4": "https://ipv4.excathedra.co/knob_valid_green.png",
5549  "v6": "https://ipv6.excathedra.co/knob_valid_green.png",
5550  "loc": "UK",
5551  "provider": "Ex Cathedra Photography",
5552  "monitor": "Steve Durbin \[email protected]\u003e",
5553  "contact": "",
5554  "reason": "",
5555  "transparent": false
5556 },
5557 "www.joram.it": {
5558  "site": "www.joram.it",
5559  "mirror": false,
5560  "hide": false,
5561  "v4": "https://ipv4.joram.it/oggetti/immagini/ipv4.png",
5562  "v6": "https://ipv6.joram.it/oggetti/immagini/ipv6.jpg",
5563  "loc": "IT",
5564  "provider": "Joram.IT",
5565  "monitor": "Servizio Partners - Joram.IT \[email protected]\u003e",
5566  "contact": "",
5567  "reason": "",
5568  "transparent": false
5569 },
5570 "www.netflash.com.cy": {
5571  "site": "www.netflash.com.cy",
5572  "mirror": false,
5573  "hide": false,
5574  "v4": "https://ipv4-test.netflash.com.cy/knob_green.png",
5575  "v6": "https://ipv6-test.netflash.com.cy/knob_green.png",
5576  "loc": "CY",
5577  "provider": "A.C. NetFlash Technologies Ltd",
5578  "monitor": "[email protected]",
5579  "contact": "",
5580  "reason": "",
5581  "transparent": false
5582 },
5583 "www.nop.hu": {
5584  "site": "www.nop.hu",
5585  "mirror": false,
5586  "hide": false,
5587  "v4": "http://ipv4.nop.hu/hosted.png",
5588  "v6": "http://ipv6.nop.hu/hosted.png",
5589  "loc": "HU",
5590  "provider": "nop.hu",
5591  "monitor": "matecs \[email protected]\u003e",
5592  "contact": "",
5593  "reason": "",
5594  "transparent": false
5595 },
5596 "www.steffann.nl": {
5597  "site": "www.steffann.nl",
5598  "mirror": false,
5599  "hide": false,
5600  "v4": "https://v4-only.steffann.nl/v4-only.png",
5601  "v6": "https://v6-only.steffann.nl/v6-only.png",
5602  "loc": "NL",
5603  "provider": "SJM Steffann Consultancy",
5604  "monitor": "Sander Steffann \[email protected]\u003e",
5605  "contact": "",
5606  "reason": "",
5607  "transparent": false
5608 }
5609};
5610/*global GIGO, jQuery, $, window, alert, Browser */
5611/*jslint browser: true */
5612
5613
5614/* Need to vary this a bit.
5615
5616Each host should:
5617
5618  try IPv4.
5619  try IPv4 again, if needed.
5620  On success,
5621
5622    try IPv6.
5623    try IPv6 again, if needed.
5624
5625The icky part is the "if needed".
5626
5627*/
5628
5629
5630
5631GIGO.url_to_hash = function (url) {
5632    var hash;
5633    url = url.replace(/\?nocache.*$/, "");
5634    hash = jQuery.md5(url);
5635    hash = hash.replace(/[^a-zA-Z0-9]/g, '');
5636    hash = hash.substring(0, 4);
5637    return hash;
5638};
5639
5640GIGO.fail_url = function (url) {
5641    var hash = GIGO.url_to_hash(url);
5642
5643
5644    // Create object, if needed.
5645    if (!GIGO.isdef(GIGO.failed_sites)) {
5646        GIGO.failed_sites = [];
5647    }
5648
5649    // Add hash, but only if not already found
5650    if (GIGO.failed_sites.indexOf(hash) < 0) {
5651        GIGO.failed_sites.push(hash);
5652    }
5653    GIGO.show_share_link();
5654};
5655
5656GIGO.was_failed_url = function (url) {
5657    var hash = GIGO.url_to_hash(url);
5658    if (!GIGO.isdef(GIGO.failed_sites)) {
5659        if (GIGO.isdef(GIGO.CGI.failed_sites)) {
5660          GIGO.failed_sites = GIGO.CGI.failed_sites.split(",");
5661        } else {
5662          GIGO.failed_sites = [];
5663        }
5664    }
5665    return (GIGO.failed_sites.indexOf(hash) >= 0);
5666};
5667
5668
5669GIGO.is_replay = function () {
5670    return (GIGO.CGI.ip4 || GIGO.CGI.ip6);
5671};
5672
5673
5674
5675GIGO.sites_table_init_1 = function (mode) {
5676    //  Create a table, replace #sitestablediv
5677    //  THIS IS FOR MIRRORS
5678    var newhtml;
5679    newhtml = '<div id="sitestablediv">';
5680    newhtml = newhtml + '<table summary="sites" id="sites" class="tablesorter">';
5681    newhtml = newhtml + "<thead><tr><th>link</th><th>location</th><th>provider</th><th>ipv6?</th><th>info</th></tr></thead>";
5682    newhtml = newhtml + "<tbody>";
5683    newhtml = newhtml + "</tbody></table>";
5684    newhtml = newhtml + "</div>";
5685
5686    // Make a table, keep the reference?
5687    jQuery("#sitestablediv").replaceWith($('<div>').html(newhtml));
5688};
5689
5690GIGO.sites_table_init_2 = function (mode) {
5691    //  Create a table, replace #sitestablediv
5692    //  THIS IS FOR MIRRORS+SITES, NO LANGUAGE INFO ETC
5693    var newhtml;
5694    newhtml = '<div id="sitestablediv">';
5695    newhtml = newhtml + '<table summary="sites" id="sites" class="tablesorter">';
5696    newhtml = newhtml + "<thead><tr><th>link</th><th>location</th><th>provider</th><th>ipv6?</th><th>info</th><th>mirror</th></tr></thead>";
5697    newhtml = newhtml + "<tbody>";
5698    newhtml = newhtml + "</tbody></table>";
5699    newhtml = newhtml + "</div>";
5700
5701    // Make a table, keep the reference?
5702    jQuery("#sitestablediv").replaceWith($('<div>').html(newhtml));
5703};
5704
5705GIGO.sites_table_init = function (mode) {
5706    if (mode === 1) {
5707        GIGO.sites_table_init_1(mode);
5708    } else if (mode === 2) {
5709        GIGO.sites_table_init_2(mode);
5710    } else {
5711        alert("bad GIGO.sites_table_init()");
5712    }
5713};
5714
5715
5716GIGO.sites_table_populate_1 = function (mode) {
5717    var i;
5718    for (i = 0; i < GIGO.sites_queue.length; i = i + 1) {
5719        GIGO.sites_display_add_record(GIGO.sites_queue[i], mode);
5720    }
5721
5722
5723    $("#sites").tablesorter({
5724        textExtraction: "complex",
5725        sortInitialOrder: "asc",
5726        headers: {
5727            0: {
5728                sorter: "text"
5729            },
5730            1: {
5731                sorter: "text"
5732            },
5733            2: {
5734                sorter: "text"
5735            },
5736            3: {
5737                sorter: "text"
5738            },
5739            4: {
5740                sorter: "text"
5741            },
5742            5: {
5743                sorter: false
5744            },
5745            6: {
5746                sorter: false
5747            }
5748        }
5749    });
5750
5751};
5752
5753GIGO.sites_table_populate_2 = function (mode) {
5754    var i;
5755    for (i = 0; i < GIGO.sites_queue.length; i = i + 1) {
5756        GIGO.sites_display_add_record(GIGO.sites_queue[i], mode);
5757    }
5758
5759
5760    $("#sites").tablesorter({
5761        textExtraction: "complex",
5762        sortInitialOrder: "asc",
5763        headers: {
5764            0: {
5765                sorter: "text"
5766            },
5767            1: {
5768                sorter: "text"
5769            },
5770            2: {
5771                sorter: "text"
5772            },
5773            3: {
5774                sorter: false
5775            },
5776            4: {
5777                sorter: false
5778            }
5779        }
5780    });
5781
5782};
5783
5784GIGO.sites_table_populate = function (mode) {
5785    if (mode === 1) {
5786        GIGO.sites_table_populate_1(mode);
5787    } else if (mode === 2) {
5788        GIGO.sites_table_populate_2(mode);
5789    } else {
5790        alert("bad GIGO.sites_table_populate()");
5791    }
5792};
5793
5794
5795
5796GIGO.sites_init = function () {
5797    GIGO.sites_queue = [];
5798};
5799
5800GIGO.sites_queue_entry = function (r) {
5801
5802    if (!r.v4) {
5803        r.v4 = "http://ipv4." + r.site + "/images-nc/hires_ok.png";
5804    }
5805    if (!r.v6) {
5806        r.v6 = "http://ipv6." + r.site + "/images-nc/hires_ok.png";
5807    }
5808
5809    // Do we have a suitable protocol?
5810    // Shrink the list, if that is what it takes.
5811    if (GIGO.protocol==="https://") {
5812      // Be a bit more strict.
5813      if (!r.v4.startsWith("https://") || !r.v6.startsWith("https://")) {
5814        console.log("GIGO.sites_queue_entry skipping %o due to https",r);
5815        return; // When viewing as https, we require all images being tested also be https
5816      }
5817    }
5818
5819
5820    // Mark up r.v4 for site analytics
5821    if (r.v4.search(/\?/)<0) {
5822      r.v4 = r.v4 + "?";
5823    }
5824    if (r.v6.search(/\?/)<0) {
5825      r.v6 = r.v6 + "?";
5826    }
5827
5828    // This might actually fail; the mirrors page does
5829    // not load GIGO.options.domain .
5830    try {
5831      r.v4 = r.v4 + "&testdomain=" + GIGO.options.domain;
5832      r.v6 = r.v6 + "&testdomain=" + GIGO.options.domain;
5833    } catch (e) {
5834      r.v4 = r.v4 + "&testdomain=" + document.location.hostname;
5835      r.v6 = r.v6 + "&testdomain=" + document.location.hostname;
5836    }
5837
5838    r.v4 = r.v4 + "&testname=sites";
5839    r.v6 = r.v6 + "&testname=sites";
5840
5841    GIGO.sites_queue.push(r);
5842};
5843
5844GIGO.sites_queue_all = function (mode) {
5845    var r, siteName;
5846
5847    console.log("in GIGO.sites_queue_all, GIGO.sites_parsed=%o",GIGO.sites_parsed);
5848    // mirrors only if mode=1
5849    // all sites if mode=2
5850    for (siteName in GIGO.sites_parsed) {
5851      r = GIGO.sites_parsed[siteName];
5852      if (mode === 1) {
5853        if (! r.mirror) continue;
5854      }
5855      GIGO.sites_queue_entry(r);
5856    }
5857
5858};
5859
5860GIGO.sites_prepare_helpdesk = function (mode) {
5861    GIGO.helpdesk.other_sites = {};
5862    GIGO.helpdesk.other_sites.finished = 0;
5863    GIGO.helpdesk.other_sites.count = 0;
5864    GIGO.helpdesk.other_sites.good = [];
5865    GIGO.helpdesk.other_sites.bad = [];
5866    if (mode > 1) {
5867        GIGO.helpdesk.other_sites.count = GIGO.sites_queue.length;
5868    }
5869
5870};
5871
5872GIGO.other_sites_info = function () {
5873    var g, b, f, c, o, text;
5874    g = GIGO.helpdesk.other_sites.good.length;
5875    b = GIGO.helpdesk.other_sites.bad.length;
5876    f = GIGO.helpdesk.other_sites.finished;
5877    c = GIGO.helpdesk.other_sites.count;
5878    o = g + b;
5879    text = "";
5880
5881    if (!c) {
5882        return "";
5883    }
5884
5885    if (f != c) {
5886        text = "(Global IPv6 connectivity being tested; " + f + "/" + c + ")";
5887        // text = text + "b=" + b + " g=" + g + " f=" + f + " c=" + c + " o=" + o + "";
5888        return text;
5889    }
5890
5891
5892    text = "OtherSites: " + g + "/" + o + " good";
5893    if (b) {
5894        text = text + ", " + b + "/" + o + " bad";
5895    }
5896
5897
5898    return text;
5899};
5900
5901GIGO.other_sites_failures = function () {
5902    var div, table, i;
5903    if (!GIGO.helpdesk.other_sites.bad.length) {
5904        return jQuery("<div>"); // morally, "nothing to show"
5905    }
5906    div = jQuery("<div>");
5907    div.append(jQuery("<p><span style='color: red'>Site(s) with failed connectivity</p>"));
5908    table = jQuery("<table>");
5909    table.append(jQuery("<tr><td>Site</td><td>Failed URL</td></tr>"));
5910    for (i = 0; i < GIGO.helpdesk.other_sites.bad.length; i = i + 1) {
5911        table.append(GIGO.sites_display_bad_r_to_tr(GIGO.helpdesk.other_sites.bad[i]));
5912    }
5913    div.append(table);
5914    return div;
5915};
5916
5917GIGO.sites_display_bad_r_to_tr = function (r) {
5918    var tr, a, parts;
5919    // r.site;
5920    // r.loc
5921    // r.provider
5922    // r.v6
5923    tr = jQuery("<tr>");
5924
5925    parts = r.v6.split("/");
5926
5927    tr.append(jQuery("<td>").text(parts[0]));
5928
5929    a = jQuery("<a>");
5930    a.text(r.v6);
5931    a.attr("href", r.v6);
5932    a.attr("target", "_blank");
5933
5934    tr.append(jQuery("<td>").append(a));
5935    return tr;
5936
5937};
5938
5939GIGO.sites_display_td_provider_div_update = function (r) {
5940    var i, td_provider_div;
5941    td_provider_div = r.refs.td_provider_div;
5942    td_provider_div.text(r.provider);
5943    for (i in arguments) {
5944        if (i > 0) {
5945            td_provider_div.append("<br/>");
5946            td_provider_div.append(arguments[i]);
5947        }
5948    }
5949};
5950
5951GIGO.sites_display_add_record = function (r, mode) {
5952    // Create new table row
5953    // Append it to existing table
5954    // Make sure that the row elements are easy to find by id
5955    var tr, td_link, td_loc, td_provider, td_status, td_info, td_mirror, mirror_button, site, td_provider_div;
5956
5957
5958    site = $("<a>", {
5959        text: r.site,
5960        href: "http://" + r.site,
5961        target: r.site
5962    });
5963    tr = $('<tr></tr>'); // Don't use .hide here.  Instead, lets show the table.  Only .hide() on failure?
5964    td_link = $("<td>").append(site);
5965    td_loc = $("<td>").text(r.loc);
5966    td_provider_div = $("<div>").text(r.provider);
5967    td_provider = $("<td>").append(td_provider_div);
5968
5969    td_status = $("<td>").append(
5970        $("<img>", { src: "/images/hires_spinner.gif"})
5971        .css("height","2em")
5972        .css("width","auto")
5973        .css("opacity", "0.1")
5974        .css("filter", "alpha(opacity=10)")
5975      );
5976    td_info = $("<td>").append($("<img>", {
5977        src: "/images/hires_info.png"
5978    }).css("height","2em").css("width","auto"));
5979
5980
5981
5982    td_info.click(function () {
5983        GIGO.sites_display_td_provider_div_update(r, $("<a>", {
5984            text: r.v4,
5985            href: r.v4,
5986            target: "_blank"
5987        }), $("<a>", {
5988            text: r.v6,
5989            href: r.v6,
5990            target: "_blank"
5991        }));
5992    });
5993
5994    if ((mode === 2) && (r.mirror)) {
5995
5996        // This should be done with jquery to avoid any potential abuse in mirrors.js, but
5997        // I can't find the right incantation.
5998        mirror_button = $("<a target='" + r.site + "' href='http://" + r.site + "'><img border=0 style='height: 2em; width: auto;' src='/images/hires_link.png'/></a>");
5999        td_mirror = $("<td>").append(mirror_button);
6000    } else {
6001        td_mirror = $("<td>").html("&nbsp;");
6002    }
6003
6004
6005
6006
6007    if (mode === 1) {
6008        tr.append(td_link, td_loc, td_provider, td_status, td_info);
6009    } else if (mode === 2) {
6010        tr.append(td_link, td_loc, td_provider, td_status, td_info, td_mirror);
6011    } else {
6012        return; // We should have had plenty of alerts already.
6013    }
6014
6015    $('#sites > tbody:last').append(tr);
6016    $('#sites').find('tbody:last').append(tr);
6017
6018
6019
6020    // Copy references to "r" object.
6021    r.refs = {};
6022    r.refs.tr = tr;
6023    r.refs.td_link = td_link;
6024    r.refs.td_loc = td_loc;
6025    r.refs.td_provider = td_provider;
6026    r.refs.td_provider_div = td_provider_div;
6027    r.refs.td_status = td_status;
6028    r.refs.td_info = td_info;
6029    r.refs.td_mirror = td_mirror;
6030};
6031
6032GIGO.sites_display_success = function (r) {
6033    var new_td;
6034    new_td = $("<td>").append($("<img>", {
6035        src: "/images/hires_ok.png"
6036    }).css("height","2em").css("width","auto"));
6037    r.refs.td_status.replaceWith(new_td);
6038    GIGO.helpdesk.other_sites.finished = GIGO.helpdesk.other_sites.finished + 1;
6039    GIGO.helpdesk.other_sites.good.push(r);
6040    GIGO.sites_update_helpdesk();
6041};
6042GIGO.sites_display_failure = function (r) {
6043    var new_td;
6044    new_td = $("<td>").append($("<img>", {
6045        src: "/images/hires_bad.png"
6046    }).css("height","2em").css("width","auto"));
6047    r.refs.td_status.replaceWith(new_td);
6048    GIGO.helpdesk.other_sites.finished = GIGO.helpdesk.other_sites.finished + 1;
6049    GIGO.helpdesk.other_sites.bad.push(r);
6050    GIGO.sites_update_helpdesk();
6051};
6052
6053GIGO.sites_display_giveup = function (r) {
6054    var new_td;
6055    new_td = $("<td>").append($("<img>", {
6056        src: "/images/hires_offline.png"
6057    }).css("height","2em").css("width","auto"));
6058    r.refs.td_status.replaceWith(new_td);
6059    GIGO.sites_display_td_provider_div_update(r, "IPv4 site down, skipping IPv6 test");
6060    GIGO.helpdesk.other_sites.finished = GIGO.helpdesk.other_sites.finished + 1;
6061    GIGO.sites_update_helpdesk();
6062};
6063
6064GIGO.sites_update_helpdesk = function () {
6065    if (GIGO.helpdesk.other_sites.count) {
6066        GIGO.finish_helpdesk();
6067    }
6068};
6069
6070
6071GIGO.sites_start_ipv6_take2 = function (r) {
6072    var url, img, img_pending;
6073
6074    if (!r.v6) {
6075        return;
6076    }
6077
6078    url = r.v6 + "?nocache=" + Math.random();
6079
6080
6081    if (GIGO.is_replay()) {
6082        img_pending = 0;
6083        if (GIGO.was_failed_url(url)) {
6084            GIGO.fail_url(url);
6085            GIGO.sites_display_failure(r);
6086        } else {
6087            GIGO.sites_display_success(r);
6088        }
6089        GIGO.sites_next_in_queue();
6090        return;
6091    }
6092
6093    setTimeout(function () {
6094
6095        // We have all the details we need to know.
6096        // We have a freshly incremented "id".
6097        // What we need now is to start an image
6098        // with handlers on it.
6099        // Finalize the URL.
6100        // Include a random number to defeat the browser cache.
6101
6102        // Create the image object.
6103        // We will keep this "off screen".
6104        img = jQuery('<img style="display:none" />');
6105        img_pending = 1;
6106
6107
6108        jQuery(img).bind({
6109            load: function () {
6110                if (img_pending) {
6111                    img_pending = 0;
6112                    GIGO.sites_display_success(r);
6113                    GIGO.sites_next_in_queue();
6114                }
6115            },
6116            error: function () {
6117                if (img_pending) {
6118                    img_pending = 0;
6119                    GIGO.fail_url(url);
6120                    GIGO.sites_display_failure(r);
6121                    GIGO.sites_next_in_queue();
6122                }
6123            }
6124        });
6125        // Fake timeout here since IE doesn't pass errors
6126        setTimeout(function () {
6127            // TODO show FAIL
6128            if (img_pending) {
6129                img_pending = 0;
6130                GIGO.fail_url(url);
6131                GIGO.sites_display_failure(r);
6132                GIGO.sites_next_in_queue();
6133            }
6134        }, GIGO.max_time);
6135        jQuery(img).attr("src", url); // Start the image loading!
6136    }, 1000);
6137
6138
6139};
6140
6141GIGO.sites_start_ipv6 = function (r) {
6142    var url, img, img_pending;
6143    // console.log("sites_start_ipv6 %o",r);
6144
6145    if (!r.v6) {
6146        return;
6147    }
6148
6149    if (GIGO.is_replay()) {
6150        GIGO.sites_start_ipv6_take2(r);
6151        return;
6152    }
6153
6154
6155    // We have all the details we need to know.
6156    // We have a freshly incremented "id".
6157    // What we need now is to start an image
6158    // with handlers on it.
6159    // Finalize the URL.
6160    // Include a random number to defeat the browser cache.
6161    url = r.v6 + "?nocache=" + Math.random();
6162
6163    // Create the image object.
6164    // We will keep this "off screen".
6165    img = jQuery('<img style="display:none" />');
6166    img_pending = 1;
6167
6168
6169    jQuery(img).bind({
6170        load: function () {
6171            if (img_pending) {
6172                img_pending = 0;
6173                GIGO.sites_display_success(r);
6174                GIGO.sites_next_in_queue();
6175            }
6176        },
6177        error: function () {
6178            if (img_pending) {
6179                img_pending = 0;
6180                GIGO.sites_start_ipv6_take2(r);
6181            }
6182        }
6183    });
6184    // Fake timeout here since IE doesn't pass errors
6185    setTimeout(function () {
6186        // TODO show FAIL
6187        if (img_pending) {
6188            img_pending = 0;
6189            GIGO.sites_start_ipv6_take2(r);
6190        }
6191    }, GIGO.max_time);
6192    jQuery(img).attr("src", url); // Start the image loading!
6193};
6194
6195
6196GIGO.sites_start_ipv4_take2 = function (r) {
6197    var url, img, img_pending;
6198    console.log("sites_start_ipv4 %o",r);
6199
6200    if (!r.v4) {
6201        return;
6202    }
6203
6204
6205    url = r.v4 + "?nocache=" + Math.random();
6206
6207
6208    if (GIGO.is_replay()) {
6209        img_pending = 0;
6210        if (GIGO.was_failed_url(url)) {
6211            GIGO.fail_url(url);
6212            GIGO.sites_display_giveup(r);
6213        } else {
6214            GIGO.sites_start_ipv6(r);
6215        }
6216        GIGO.sites_next_in_queue();
6217        return;
6218    }
6219
6220
6221
6222
6223    // Intentionally delay by a second
6224    // This gives a chance for the DNS to eventually
6225    // resolve, in case that was the source of the error.
6226    setTimeout(function () {
6227
6228        r.refs.td_status.find('img').css("opacity", "1.0").css("filter", "alpha(opacity=100)");
6229
6230        img = jQuery('<img style="display:none" />');
6231        img_pending = 1;
6232
6233        jQuery(img).bind({
6234            load: function () {
6235                img_pending = 0;
6236                GIGO.sites_start_ipv6(r);
6237            },
6238            error: function () {
6239                if (img_pending) {
6240                    img_pending = 0;
6241                    GIGO.fail_url(url);
6242                    GIGO.sites_display_giveup(r);
6243                    GIGO.sites_next_in_queue();
6244                }
6245            }
6246        });
6247        setTimeout(function () {
6248            // TODO show FAIL
6249            if (img_pending) {
6250                img_pending = 0;
6251                GIGO.fail_url(url);
6252                GIGO.sites_display_giveup(r);
6253                GIGO.sites_next_in_queue();
6254            }
6255        }, GIGO.max_time);
6256        // Fake timeout here since IE doesn't pass errors
6257        jQuery(img).attr("src", url); // Start the image loading!
6258    }, 1000);
6259};
6260
6261
6262
6263GIGO.sites_start_ipv4 = function (r) {
6264    var url, img, img_pending;
6265
6266
6267    if (!r.v4) {
6268        return;
6269    }
6270
6271    // Visiting the IPv6 specific site
6272    if (window.location.hostname.toLocaleLowerCase().startsWith("ipv6."))  {
6273        GIGO.sites_start_ipv6(r);
6274        return;
6275    }
6276
6277    // OR the beta site
6278    if (window.location.hostname.toLocaleLowerCase().startsWith("beta."))  {
6279        GIGO.sites_start_ipv6(r);
6280        return;
6281    }
6282
6283    // IPv6 only? Brave fellow.
6284    if ((!GIGO.results.ipv4.ip) && (GIGO.results.ipv6.ip)) {
6285        GIGO.sites_start_ipv6(r);
6286        return;
6287    }
6288
6289    if (GIGO.is_replay()) {
6290        GIGO.sites_start_ipv4_take2(r);
6291        return;
6292    }
6293
6294
6295    r.refs.td_status.find('img').css("opacity", "1.0").css("filter", "alpha(opacity=100)");
6296
6297    url = r.v4 + "?nocache=" + Math.random();
6298    img = jQuery('<img style="display:none" />');
6299    img_pending = 1;
6300
6301
6302    jQuery(img).bind({
6303        load: function () {
6304            if (img_pending) {
6305                img_pending = 0;
6306                GIGO.sites_start_ipv6(r);
6307            }
6308        },
6309        error: function () {
6310            if (img_pending) {
6311                img_pending = 0;
6312
6313                GIGO.sites_start_ipv4_take2(r);
6314            }
6315        }
6316    });
6317    setTimeout(function () {
6318        // TODO show FAIL
6319        if (img_pending) {
6320            img_pending = 0;
6321            GIGO.sites_start_ipv4_take2(r);
6322        }
6323    }, GIGO.max_time);
6324    // Fake timeout here since IE doesn't pass errors
6325    jQuery(img).attr("src", url); // Start the image loading!
6326};
6327
6328
6329GIGO.sites_next_in_queue = function () {
6330    var r;
6331    if (GIGO.sites_queue.length > 0) {
6332        r = GIGO.sites_queue.shift();
6333        GIGO.sites_start_ipv4(r);
6334    }
6335};
6336
6337GIGO.sites_start_tests = function () {
6338    // 9 parallel runs, spaced a bit a part.
6339    if (0 && GIGO.is_replay()) {
6340        while (GIGO.sites_queue.length > 0) {
6341            GIGO.sites_next_in_queue();
6342        }
6343    } else {
6344        setTimeout(GIGO.sites_next_in_queue, 1);
6345        setTimeout(GIGO.sites_next_in_queue, 75);
6346        setTimeout(GIGO.sites_next_in_queue, 150);
6347        setTimeout(GIGO.sites_next_in_queue, 225);
6348        setTimeout(GIGO.sites_next_in_queue, 300);
6349        setTimeout(GIGO.sites_next_in_queue, 375);
6350        setTimeout(GIGO.sites_next_in_queue, 450);
6351        setTimeout(GIGO.sites_next_in_queue, 525);
6352        setTimeout(GIGO.sites_next_in_queue, 600);
6353    }
6354};
6355
6356GIGO.test_sites = function (mode) {
6357    GIGO.sites_init(mode);
6358    GIGO.sites_queue_all(mode);
6359    GIGO.fisherYates(GIGO.sites_queue);
6360    GIGO.sites_prepare_helpdesk(mode);
6361    GIGO.sites_table_init(mode);
6362    GIGO.sites_table_populate(mode);
6363    GIGO.sites_start_tests(mode);
6364};
6365
6366
6367GIGO.fisherYates = function (myArray) {
6368    var i, j, tempi, tempj;
6369    i = myArray.length;
6370    if (i === 0) {
6371        return;
6372    }
6373    while (i > 0) {
6374        i = i - 1;
6375        j = Math.floor(Math.random() * (i + 1));
6376        tempi = myArray[i];
6377        tempj = myArray[j];
6378        myArray[i] = tempj;
6379        myArray[j] = tempi;
6380    }
6381};
6382
6383/*global GIGO, Browser, unescape */
6384/*jslint browser: true */
6385
6386// Call this early, to enable the isp helpdesk tab
6387
6388//GIGO.list_of_ipv4 = ["a", "ds4"];
6389//GIGO.list_of_ipv6 = ["aaaa", "ds6", "test_v6mtu"];
6390
6391
6392GIGO.start_helpdesk = function () {
6393    var want_helpdesk = 0;
6394    if (GIGO.CGI.isp) {
6395        want_helpdesk = 1;
6396    }
6397    if (GIGO.CGI.helpdesk) {
6398        want_helpdesk = 1;
6399    }
6400    if (String(location.pathname).match(/\b(isp|helpdesk)\b/i)) {
6401        want_helpdesk = 1;
6402    }
6403    if (String(location.hostname).match(/\b(isp|helpdesk)\b/i)) {
6404        want_helpdesk = 1;
6405    }
6406    if (String(location.hash).match(/^(isp|helpdesk)\$/i)) {
6407        want_helpdesk = 1;
6408    }
6409
6410    if (want_helpdesk) {
6411        GIGO.tabnav("helpdesk");
6412    } else {
6413        $("#tabbutton_helpdesk_link").addClass("navright");
6414    }
6415
6416};
6417
6418
6419
6420GIGO.helpdesk_ob_status = function (n) {
6421    var s = GIGO.results.tests[n].status;
6422    if (s === "ok") return "g";
6423    if (s === "slow") return "g";
6424    if (s === "bad") return "b";
6425    if (s === "timeout") return "t";
6426    if (s === "skipped") return "x";
6427};
6428GIGO.helpdesk_ob_type = function () {
6429    //# global,bad,teredo,6to4,asn(different)
6430    var t = "b";
6431    if ((GIGO.results.ipv6) && (GIGO.results.ipv6.ip)) {
6432        t = "g"; // By default it must have a global address, right?
6433        if (GIGO.helpdesk.teredo) {
6434            t = "t"; // teredo
6435        }
6436        if (GIGO.helpdesk.sixfour) {
6437            t = "6"; // 6to4
6438        }
6439    }
6440    return t;
6441};
6442
6443
6444GIGO.helpdesk_score = function () {
6445    var mini_helpdesk, score;
6446
6447    // GIGO.results.tests[x].status
6448    var status_a = GIGO.helpdesk_ob_status("test_a");
6449    var status_aaaa = GIGO.helpdesk_ob_status("test_aaaa");
6450    var status_ipv6_type = GIGO.helpdesk_ob_type();
6451
6452    var status = status_a + ":" + status_aaaa + status_ipv6_type;
6453    var ob = {};
6454
6455    //console.log("helpdesk status code %o",status);
6456
6457    ob.found = GIGO.sym_helpdesk[status];
6458    ob.qcode = GIGO.sym_helpdesk_qcode[ob.found];
6459
6460    if (ob.found) {
6461        if (GIGO.helpdesk.failed_pmtud) {
6462            ob.found = ob.found + ", Potential MTU issues";
6463            ob.qcode = ob.qcode + ",mtu";
6464        }
6465        if (GIGO.helpdesk.mini_primary.match(/s/)) {
6466            ob.found = ob.found + ", Slow";
6467            ob.qcode = ob.qcode + ",slow";
6468        }
6469        return ob;
6470    }
6471    return;
6472};
6473
6474GIGO.helpdesk_good_bad_slow = function (a) {
6475    var slow = 0;
6476    var good = 0;
6477    var tout = 0;
6478    var i = 0;
6479    for (i = 0; i < a.length; i = i + 1) {
6480        if (GIGO.results.tests[a[i]].status === "ok") {
6481            good = 1;
6482        }
6483        if (GIGO.results.tests[a[i]].status === "slow") {
6484            slow = 1;
6485        }
6486        if (GIGO.results.tests[a[i]].status === "timeout") {
6487            tout = 1;
6488        }
6489    }
6490    if (tout) return "Timeout";
6491    if (slow) return "Slow";
6492    if (good) return "Good";
6493    return "Bad";
6494};
6495
6496GIGO.helpdesk_ipv4_info = function () {
6497    var test_a, test_asn4, s;
6498    test_a = GIGO.results.tests.test_a;
6499    test_asn4 = GIGO.results.tests.test_asn4;
6500
6501    // status
6502    // ipinfo.ip
6503    // ipinfo.asn
6504    // ipinfo.asn_name
6505    // time_ms
6506
6507    if ((test_a.ipinfo) && (test_a.ipinfo.ip)) {
6508        s = "IPv4: ";
6509        s = s + GIGO.helpdesk_good_bad_slow(["test_a", "test_ds4"]);
6510        if (test_asn4 && test_asn4.ipinfo && test_asn4.ipinfo.asn) {
6511            s = s + ", AS" + test_asn4.ipinfo.asn + " - ";
6512            s = s + test_asn4.ipinfo.asn_name;
6513        }
6514        return s;
6515    } else {
6516        return "IPv4: no";
6517    }
6518};
6519
6520GIGO.helpdesk_ipv6_info = function () {
6521    var test_aaaa, test_asn6, s;
6522    test_aaaa = GIGO.results.tests.test_aaaa;
6523    test_asn6 = GIGO.results.tests.test_asn6;
6524
6525
6526    // status
6527    // ipinfo.ip
6528    // ipinfo.asn
6529    // ipinfo.asn_name
6530    // time_ms
6531
6532
6533    // We need to warn if any of the IPv6 tries timed out
6534
6535    if ((test_aaaa.ipinfo) && (test_aaaa.ipinfo.ip)) {
6536        s = "IPv6: ";
6537        s = s + GIGO.helpdesk_good_bad_slow(["test_aaaa", "test_ds6",  "test_v6mtu"]);
6538        if (test_asn6 && test_asn6.ipinfo && test_asn6.ipinfo.asn) {
6539            s = s + ", AS" + test_asn6.ipinfo.asn + " - ";
6540            s = s + test_asn6.ipinfo.asn_name;
6541        }
6542        return s;
6543    } else {
6544
6545        if ((GIGO.results.tests.test_aaaa) && (GIGO.results.tests.test_aaaa.status) && (GIGO.results.tests.test_aaaa.status === "timeout")) {
6546            return "IPv6: broken";
6547        }
6548        if ((GIGO.results.tests.test_ds) && (GIGO.results.tests.test_ds.status) && (GIGO.results.tests.test_ds.status === "timeout")) {
6549            return "IPv6: broken";
6550        }
6551        if ((GIGO.results.tests.test_ipv6) && (GIGO.results.tests.test_ipv6.status) && (GIGO.results.tests.test_ipv6.status === "timeout")) {
6552            return "IPv6: broken";
6553        }
6554        return "IPv6: no";
6555    }
6556};
6557
6558
6559// call this late to populate the helpdesk tab
6560GIGO.finish_helpdesk = function () {
6561    var code, div;
6562    if (!GIGO.results.debug_code) {
6563        return; // Too soon.
6564    }
6565
6566    // Show the replay url
6567    jQuery("#replayurldiv").show();
6568
6569    code = GIGO.helpdesk_score();
6570
6571    div = jQuery("<div>", {
6572        id: "helpdesk_content"
6573    });
6574
6575    //  div.append("<div class=beta>BETA  -This tab is a work in progress.</div>");
6576
6577    div.append(jQuery("<p>").append("Your Internet help desk may ask you for the information below."));
6578
6579    if ((code) && (code.qcode)) {
6580        div.append(jQuery("<p>
6580").append(jQuery("<span class=helpdeskcode>").text("Help desk code: " + code.qcode)));
6581    }
6582    if ((code) && (code.found)) {
6583        div.append(jQuery("<p>").append(jQuery("<b>").text(code.found)));
6584    }
6585
6586    // GIGO.results.ipv4 and ipv6, have our ASN info.
6587
6588    //    div.append(jQuery("<div>").text(s));
6589    div.append(jQuery("<div>").text(GIGO.helpdesk_ipv4_info()));
6590    div.append(jQuery("<div>").text(GIGO.helpdesk_ipv6_info()));
6591    if (GIGO.helpdesk.other_sites && GIGO.helpdesk.other_sites.count) {
6592        div.append(jQuery("<div>").text(GIGO.other_sites_info()));
6593    }
6594
6595    div.append("<div><p></p></div>"); // Space.
6596    if ((GIGO.results.ipv4) && (GIGO.results.ipv4.ip)) {
6597        div.append(jQuery("<div>").text("IPv4 address: " + GIGO.results.ipv4.ip));
6598    }
6599    if ((GIGO.results.ipv6) && (GIGO.results.ipv6.ip)) {
6600        div.append(jQuery("<div>").text("IPv6 address: " + GIGO.results.ipv6.ip));
6601    }
6602    div.append("<div><p></p></div>"); // Space.
6603
6604    if (GIGO.helpdesk.other_sites) {
6605        div.append(GIGO.other_sites_failures());
6606    }
6607
6608
6609    //  IPv4: Good, AS1234, CableCo
6610    // IPv6: Good, Teredo, Not Preferred
6611    // OtherSites: 40/40 Good
6612
6613    // IPv4 address: 192.0.2.1
6614    // IPv6 address: 2001:0c000:201::1
6615
6616
6617    $("#helpdesk_content").replaceWith(div);
6618
6619
6620
6621
6622    //     $("#helpdesk_content")
6623
6624    // GIGO.results.tokens
6625    // GIGO.results.score_transition
6626    // GIGO.results.score_strict
6627    // GIGO.results.debug_code
6628    // GIGO.results.tokens_expanded
6629    // GIGO.results.mini_primary
6630    // GIGO.results.mini_secondary
6631
6632    // This is meant to be ran several times; each time will replace
6633    // #helpdesk_content
6634
6635    // First time replaced, will be before the "other sites" tab starts.
6636    // If we have IPV6, then it should say "checking other sites.."
6637    // And perhaps update only when done?
6638
6639};
6640
6641/* We will pulse specific CSS elements, 
6642cycling through colors ranging from yellow to white */
6643
6644GIGO.pulse_background_speed = 250;
6645GIGO.pulse_background_colors_function = function () {
6646 if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
6647  // dark mode
6648  return [
6649   "#3b3528",
6650   "#59503c",
6651   "#786c50",
6652   "#968150",
6653   "#968150",
6654   "#786c50",
6655   "#59503c",
6656   "#3b3528"];
6657 } else {
6658  return  [
6659   "#fffeee",
6660   "#fffeee",
6661   "#fffddd",
6662   "#fffccc",
6663   "#fffaaa",
6664   "#ffe6aa",
6665   "#fffaaa",
6666   "#fffccc",
6667   "#fffddd",
6668   "#fffeee",
6669   "#fffeee"];
6670 }
6671}
6672
6673
6674GIGO.pulse_background_colors = GIGO.pulse_background_colors_function();
6675
6676// On change, refresh the colors.
6677window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => {
6678 GIGO.pulse_background_colors = GIGO.pulse_background_colors_function();
6679});
6680
6681GIGO.pulse_on = function () {
6682 var n = GIGO.pulse_background_colors.shift();
6683 GIGO.pulse_background_colors.push(n);
6684 jQuery(".help_popup").css("background-color",n);
6685 jQuery("#comments_faq_link").css("background-color",n);
6686 setTimeout( function() {
6687    GIGO.pulse_on();
6688 }, GIGO.pulse_background_speed);   
6689}
6690
6691/*global GIGO, MirrorConfig, jQuery,  window,  alert,  Browser */
6692/*jslint browser: true */
6693/*jslint regexp: true */
6694
6695
6696GIGO.prepare_fake = function () {
6697    var i, funcname, shortname;
6698    for (i = 0; i < GIGO.queue.length; i = i + 1) {
6699        funcname = GIGO.queue[i][2];
6700        shortname = funcname.replace(/^test_/, "");
6701        if (GIGO.CGI[shortname]) {
6702            GIGO.override = 1;
6703            GIGO.overrides[funcname] = GIGO.CGI[shortname];
6704            GIGO.use_queue = 1;
6705        }
6706    }
6707    if ((GIGO.isdef(GIGO.CGI.ip4)) || (GIGO.isdef(GIGO.CGI.ip6))) {
6708        GIGO.override = 1;
6709    }
6710};
6711
6712
6713GIGO.override_id = function (id, url) {
6714    var tests, this_test, parts, status, protocol, whichasn;
6715    tests = GIGO.results.tests; // Convenience
6716    if (!(tests.hasOwnProperty(id))) {
6717        tests[id] = {};
6718    }
6719
6720    tests[id] = {};
6721    this_test = tests[id];
6722    this_test.url = url;
6723    this_test.start_time = GIGO.getms();
6724    this_test.ipinfo = {};
6725
6726    GIGO.update_url(id);
6727
6728    // TODO  copy from ipinfo
6729    parts = GIGO.overrides[id].split(/,/);
6730
6731    // parts[0] = status
6732    // parts[1] = time
6733    // parts[2] = protocol
6734
6735    // TODO I know this is totally gonna cause problems when the url is missing data
6736    status = parts[0];
6737    protocol = parts[2];
6738    if (!protocol) {
6739        if ((id === "test_aaaa") ||  (id === "test_v6mtu") || (id === "test_v6ns") || (id === "test_dsmtu") || (id === "test_ds")) {
6740            protocol = "ipv6";
6741        } else {
6742            protocol = "ipv4";
6743        }
6744    }
6745    // Is it abbreviated?
6746    if (protocol==="6" || protocol==="4") {
6747      protocol="ipv"+protocol;
6748    }
6749
6750    whichasn = "test_asn" + protocol.replace(/^ipv/, "");
6751
6752    if (status === "ok") {
6753        for (var key in tests[whichasn].ipinfo) {
6754            if (!key.match(/^asn/)) {
6755                this_test.ipinfo[key] = tests[whichasn].ipinfo[key];
6756            }
6757        }
6758        this_test.status = status;
6759        this_test.time_ms = parseInt(parts[1]) || 1;
6760    }
6761    if (status === "slow") {
6762        for (var key in tests[whichasn].ipinfo) {
6763            if (!key.match(/^asn/)) {
6764                this_test.ipinfo[key] = tests[whichasn].ipinfo[key];
6765            }
6766        }
6767        this_test.status = status;
6768        this_test.time_ms = parseInt(parts[1]) || (GIGO.slow + 1);
6769    }
6770    if (status === "bad") {
6771        this_test.ipinfo = {};
6772        this_test.status = status;
6773        this_test.time_ms = parseInt(parts[1]) || 1;
6774    }
6775    if (status === "timeout") {
6776        this_test.ipinfo = {};
6777        this_test.status = status;
6778        this_test.time_ms = parseInt(parts[1]) || (GIGO.max_time + 1);
6779    }
6780    if (status === "skipped") {
6781        this_test.ipinfo = {};
6782        this_test.status = status;
6783        this_test.time_ms = parseInt(parts[1]) || (0);
6784    }
6785
6786    if (id === "test_ds") {
6787        // We need to populate test_ds4 and test_ds6  in much the same way that GIGO.test_type_json() does
6788        if (this_test.ipinfo.type === "ipv6") {
6789            tests.test_ds6 = {
6790                url: this_test.url,
6791                time_ms: this_test.time_ms,
6792                status: this_test.status
6793            };
6794            tests.test_ds4 = {
6795                url: this_test.url,
6796                time_ms: this_test.time_ms,
6797                status: "bad"
6798            };
6799        } else {
6800            tests.test_ds4 = {
6801                url: this_test.url,
6802                time_ms: this_test.time_ms,
6803                status: this_test.status
6804            };
6805            tests.test_ds6 = {
6806                url: this_test.url,
6807                time_ms: this_test.time_ms,
6808                status: "bad"
6809            };
6810        }
6811    }
6812    this_test.ipinfo.type=protocol;
6813
6814};
6815
6816GIGO.override_id_ip = function (id) {
6817    var tests, this_test, parts, status, protocol, whichasn;
6818    tests = GIGO.results.tests; // Convenience
6819    this_test = tests[id];
6820    if (!this_test) {
6821        return;
6822    }
6823    if (!this_test.ipinfo.type) {
6824        return;
6825    }
6826    whichasn = "test_asn" + this_test.ipinfo.type.replace(/^ipv/, "");
6827
6828    this_test.ipinfo = {};
6829
6830
6831    for (var key in tests[whichasn].ipinfo) {
6832        if (!key.match(/^asn/)) {
6833            this_test.ipinfo[key] = tests[whichasn].ipinfo[key];
6834        }
6835    }
6836};
6837
6838
6839GIGO.ood_url = function () {
6840    var url;
6841    try {
6842        hash = jQuery.md5(MirrorConfig.load.domain);
6843        hash = hash.replace(/[^a-zA-Z0-9]/g, '');
6844        hash = hash.substring(0, 8);
6845        url = "//test-ipv6.com/images/ood_" + hash + ".png";
6846    } catch (err) {
6847    };
6848    return url;
6849};
6850
6851/*global GIGO, MirrorConfig, jQuery,  window,  alert,  Browser */
6852/*jslint browser: true */
6853/*jslint regexp: true */
6854
6855
6856GIGO.update_ipaddress = function (ipinfo) {
6857    // ipinfo:  callback({"ip":"69.62.233.151","type":"ipv4","subtype":"","public":1,"filler":""});
6858
6859    // What if "ip" is  "192.0.2.1, 192.0.2.1"?  Reduce it.
6860    if ((ipinfo) && (ipinfo.ip)) {
6861        let sp = ipinfo.ip.split(", ");
6862        let use = sp[0];
6863        for (let element of sp.values()) {
6864            if (element !== sp[0]) {
6865                use=ipinfo.ip;
6866            }
6867        }
6868        ipinfo.ip=use ;
6869    }
6870
6871    if (ipinfo.type === "ipv4") {
6872        if (!GIGO.results.ipv4.asn) {
6873            GIGO.results.ipv4 = ipinfo;
6874        }
6875    }
6876    if (ipinfo.type === "ipv6") {
6877        if (!GIGO.results.ipv6.asn) {
6878            GIGO.results.ipv6 = ipinfo;
6879        }
6880    }
6881};
6882
6883GIGO.test_type_delayed = function (url, id) {
6884
6885    // We will use this to stagger the start time_ms.
6886    // Since javascript has no "sleep" the next best
6887    // thing appears to be to set a timeout, and on timeout,
6888    // do what we really wanted.
6889    // We increase the timeout value each time we run this, so
6890    // that each thread time_ms out at a later time, to prevent
6891    // all tests from running INSTANTLY.
6892    // This is principally to work around IE problems
6893    // with too many jsonP queries initiating at once.
6894    GIGO.slowcount = GIGO.slowcount + 1;
6895    setTimeout(function () {
6896        GIGO.test_type(url, id);
6897    }, GIGO.slowcount * GIGO.slowcount_delay);
6898};
6899
6900GIGO.finish_test = function (id) {
6901    var total_tests = GIGO.queue.length + GIGO.dequeued.length; // Once for main text, once for fallback image test
6902    GIGO.tests_finished = GIGO.tests_finished + 1;
6903    GIGO.update_progress(GIGO);
6904    GIGO.update_status(id);
6905    if (GIGO.tests_finished >= total_tests) {
6906        GIGO.check_results();
6907    }
6908    GIGO.next_in_queue(); // Start next test, if available
6909    GIGO.show_debug();
6910};
6911
6912
6913GIGO.test_type_skip = function (url, id) {
6914    // name = dns name to fetch
6915    // id = which <div> to update
6916    var tests, this_test;
6917
6918
6919
6920    // Let us also add in some hints for mirror operators
6921    if (url.search(/\?/) < 0) {
6922        url = url + "?";
6923    }
6924    url = url + "&testdomain=" + GIGO.options.domain;
6925    url = url + "&testname=" + id;
6926    if (Browser.opera) {
6927        url = url + "&random=" + Math.random();
6928    }
6929
6930
6931    tests = GIGO.results.tests; // Convenience
6932    if (!(tests.hasOwnProperty(id))) {
6933        tests[id] = {};
6934    }
6935    this_test = tests[id];
6936
6937    this_test.start_time = GIGO.getms(); // Will use to find how long we ran
6938    this_test.url = url; // For later display of test urls
6939    // Update status to "Started" if we don't have any time for this yet
6940
6941
6942
6943    this_test.time_ms=0;
6944    this_test.status = "skipped";
6945    GIGO.finish_test(id);
6946    GIGO.update_url(id);
6947    GIGO.show_debug();
6948
6949};
6950
6951
6952GIGO.test_type_json = function (url, id) {
6953    // name = dns name to fetch
6954    // id = which <div> to update
6955    var tests, this_test;
6956
6957
6958
6959    // Let us also add in some hints for mirror operators
6960    if (url.search(/\?/) < 0) {
6961      url = url + "?";
6962    }
6963    url = url + "&testdomain=" + GIGO.options.domain;
6964    url = url + "&testname=" + id;
6965    if (Browser.opera) {
6966            url = url + "&random=" + Math.random();
6967    }
6968
6969
6970    tests = GIGO.results.tests; // Convenience
6971    if (!(tests.hasOwnProperty(id))) {
6972        tests[id] = {};
6973    }
6974    this_test = tests[id];
6975
6976    this_test.start_time = GIGO.getms(); // Will use to find how long we ran
6977    this_test.url = url; // For later display of test urls
6978    // Update status to "Started" if we don't have any time for this yet
6979
6980
6981
6982
6983    if (GIGO.overrides && GIGO.overrides[id]) {
6984        // oh, we're faking this one.  TODO
6985        // we can take a lot of short cuts.
6986        GIGO.override_id(id, url);
6987        GIGO.finish_test(id);
6988        GIGO.update_url(id);
6989        GIGO.show_debug();
6990        return;
6991    }
6992
6993
6994    GIGO.update_url(id);
6995
6996    // Initiate new query.  Based on pass/fail, update status.
6997    jQuery.jsonp({
6998        "url": url,
6999        "cache": true,
7000        "pageCache": false,
7001        "timeout": GIGO.max_time,
7002
7003        "success": function (ipinfo) {
7004            // Keep track of IP information we receive
7005            var delta;
7006
7007            delete ipinfo.full; // Don't need this polluting anything.
7008            delete ipinfo.padding; // Don't need this polluting anything.
7009            this_test.ipinfo = ipinfo; // Record the IP address reported from this test
7010            if (GIGO.override) {
7011                GIGO.override_id_ip(id);
7012            }
7013            GIGO.update_ipaddress(this_test.ipinfo); // Make note of our IPv4 or IPv6 address based on the test
7014            GIGO.update_ip(id); // callback for presentation
7015            delta = GIGO.getms() - this_test.start_time;
7016            if (GIGO.isdef(this_test.time_ms)) {
7017                if (delta < this_test.time_ms) {
7018                    this_test.time_ms = delta;
7019                }
7020            } else {
7021                this_test.time_ms = delta;
7022            }
7023            this_test.status = (this_test.time_ms < GIGO.slow) ? "ok" : "slow";
7024
7025
7026            // Look for dual stack
7027            if (id === "test_ds") {
7028                // ds4 and ds6 have the same time; but if one is good, the other must be bad,
7029                // since we can't possibly connect to both with a single DNS name
7030                if (ipinfo.type === "ipv6") {
7031                    tests.test_ds6 = {
7032                        url: this_test.url,
7033                        time_ms: this_test.time_ms,
7034                        status: this_test.status
7035                    };
7036                    tests.test_ds4 = {
7037                        url: this_test.url,
7038                        time_ms: this_test.time_ms,
7039                        status: "bad"
7040                    };
7041                } else {
7042                    tests.test_ds4 = {
7043                        url: this_test.url,
7044                        time_ms: this_test.time_ms,
7045                        status: this_test.status
7046                    };
7047                    tests.test_ds6 = {
7048                        url: this_test.url,
7049                        time_ms: this_test.time_ms,
7050                        status: "bad"
7051                    };
7052                }
7053            }
7054
7055            GIGO.finish_test(id);
7056
7057
7058        },
7059        "error": function (d, msg) {
7060            var delta;
7061
7062            console.log("test_type_json url=%o id=%o d=%o msg=%o",url,id,d,msg);
7063
7064            delta = GIGO.getms() - this_test.start_time;
7065            if (GIGO.isdef(this_test.time_ms)) {
7066                if (delta < this_test.time_ms) {
7067                    this_test.time_ms = delta;
7068                }
7069            } else {
7070                this_test.time_ms = delta;
7071            }
7072            this_test.status = (this_test.time_ms < GIGO.slow) ? "bad" : "timeout";
7073
7074            // Look for dual stack
7075            if (id === "test_ds") {
7076                tests.test_ds6 = {
7077                    url: this_test.url,
7078                    time_ms: this_test.time_ms,
7079                    status: this_test.status
7080                };
7081                tests.test_ds4 = {
7082                    url: this_test.url,
7083                    time_ms: this_test.time_ms,
7084                    status: this_test.status
7085                };
7086            }
7087
7088
7089            // Fallback to image test, if the primary tests fail.  Just in case some filter blocked the script fetches.
7090            GIGO.finish_test(id);
7091            GIGO.queue.push(["test_type_img", GIGO.options.url[id + "_img"], id + "_img"]);
7092        }
7093    });
7094
7095    // Perform callback for presentation
7096    GIGO.update_url(id);
7097    GIGO.show_debug();
7098
7099};
7100
7101
7102GIGO.test_type_json_only = function (url, id) {
7103    // name = dns name to fetch
7104    // id = which <div> to update
7105    var tests, this_test;
7106
7107
7108    if (url.search(/\?/) < 0) {
7109      url = url + "?";
7110    }
7111    url = url + "&testdomain=" + GIGO.options.domain;
7112    url = url + "&testname=" + id;
7113    if (Browser.opera) {
7114            url = url + "&random=" + Math.random();
7115    }
7116
7117
7118
7119
7120    tests = GIGO.results.tests; // Convenience
7121    if (!(tests.hasOwnProperty(id))) {
7122        tests[id] = {};
7123    }
7124    this_test = tests[id];
7125
7126    this_test.start_time = GIGO.getms(); // Will use to find how long we ran
7127    this_test.url = url; // For later display of test urls
7128    // Update status to "Started" if we don't have any time for this yet
7129    GIGO.update_url(id);
7130
7131
7132
7133    if ((id === "test_asn4") && (GIGO.isdef(GIGO.CGI.ip4))) {
7134        if ((GIGO.CGI.ip4) && (GIGO.CGI.ip4.match(/^[0-9abcdef.:]+$/))) {
7135            url = url  + "&testip=" + GIGO.CGI.ip4;
7136            // url = "/ip/?callback=?&asn=1&testip=" + GIGO.CGI.ip4;
7137            // url = url + "&testdomain=" + GIGO.options.domain;
7138            // url = ur
7138l + "&testname=" + id;
7139            this_test.url = url; // For later display of test urls
7140            GIGO.update_url(id);
7141        } else {
7142            this_test.ipinfo = {};
7143            this_test.status = "bad";
7144            this_test.time_ms = 1;
7145            GIGO.finish_test(id);
7146            GIGO.update_url(id);
7147            GIGO.show_debug();
7148            return;
7149        }
7150    }
7151    if ((id === "test_asn6") && (GIGO.isdef(GIGO.CGI.ip6))) {
7152        if ((GIGO.CGI.ip6) && (GIGO.CGI.ip6.match(/^[0-9abcdef.:]+$/))) {
7153            url = url  + "&testip=" + GIGO.CGI.ip6;
7154            //
7155            // url = "/ip/?callback=?&asn=1&testip=" + GIGO.CGI.ip6;
7156            // url = url + "&testdomain=" + GIGO.options.domain;
7157            // url = url + "&testname=" + id;
7158            this_test.url = url; // For later display of test urls
7159            GIGO.update_url(id);
7160        } else {
7161            this_test.ipinfo = {};
7162            this_test.status = "bad";
7163            this_test.time_ms = 1;
7164            GIGO.finish_test(id);
7165            GIGO.update_url(id);
7166            GIGO.show_debug();
7167            return;
7168        }
7169    }
7170
7171
7172
7173
7174
7175    // Initiate new query.  Based on pass/fail, update status.
7176    jQuery.jsonp({
7177        "url": url,
7178        "cache": true,
7179        "pageCache": false,
7180        "timeout": GIGO.max_time,
7181
7182        "success": function (ipinfo) {
7183            // Keep track of IP information we receive
7184            var delta;
7185
7186            delete ipinfo.full; // Don't need this polluting anything.
7187            delete ipinfo.padding; // Don't need this polluting anything.
7188            this_test.ipinfo = ipinfo; // Record the IP address reported from this test
7189            GIGO.update_ipaddress(this_test.ipinfo); // Make note of our IPv4 or IPv6 address based on the test
7190            GIGO.update_ip(id); // callback for presentation
7191            delta = GIGO.getms() - this_test.start_time;
7192            if (GIGO.isdef(this_test.time_ms)) {
7193                if (delta < this_test.time_ms) {
7194                    this_test.time_ms = delta;
7195                }
7196            } else {
7197                this_test.time_ms = delta;
7198            }
7199            this_test.status = (this_test.time_ms < GIGO.slow) ? "ok" : "slow";
7200
7201
7202
7203            GIGO.finish_test(id);
7204
7205
7206        },
7207        "error": function (d, msg) {
7208            var delta;
7209
7210            delta = GIGO.getms() - this_test.start_time;
7211            if (GIGO.isdef(this_test.time_ms)) {
7212                if (delta < this_test.time_ms) {
7213                    this_test.time_ms = delta;
7214                }
7215            } else {
7216                this_test.time_ms = delta;
7217            }
7218            this_test.status = (this_test.time_ms < GIGO.slow) ? "bad" : "timeout";
7219
7220
7221            GIGO.finish_test(id);
7222        }
7223    });
7224
7225    // Perform callback for presentation
7226    GIGO.update_url(id);
7227    GIGO.show_debug();
7228};
7229
7230
7231GIGO.test_type_img = function (url, id) {
7232    // name = dns name to fetch
7233    // id = which <div> to update
7234    var tests, this_test, img, img_pending;
7235
7236    if (url.search(/\?/) < 0) {
7237          url = url + "?";
7238    }
7239    url = url + "&testdomain=" + GIGO.options.domain;
7240    url = url + "&testname=" + id;
7241    if (Browser.opera) {
7242            url = url + "&random=" + Math.random();
7243    }
7244
7245    tests = GIGO.results.tests; // Convenience
7246    if (!(tests.hasOwnProperty(id))) {
7247        tests[id] = {};
7248    }
7249    this_test = tests[id];
7250
7251    this_test.start_time = GIGO.getms(); // Will use to find how long we ran
7252    this_test.url = url; // For later display of test urls
7253    // Update status to "Started" if we don't have any time for this yet
7254    GIGO.update_url(id);
7255
7256    // Create image.
7257    // Attach handlers to the image.
7258    // Create a timer to artificially timeout imgs
7259    img_pending = 1;
7260
7261    img = jQuery('<img style="display:none" />');
7262
7263    jQuery(img).bind({
7264        load: function () {
7265            var delta;
7266
7267            if (img_pending) {
7268                img_pending = 0;
7269                delta = GIGO.getms() - this_test.start_time;
7270                if (GIGO.isdef(this_test.time_ms)) {
7271                    if (delta < this_test.time_ms) {
7272                        this_test.time_ms = delta;
7273                    }
7274                } else {
7275                    this_test.time_ms = delta;
7276                }
7277                this_test.image = 1;
7278                this_test.status = (this_test.time_ms < GIGO.slow) ? "ok" : "slow";
7279                if (this_test.test_ms > GIGO.max_time) {
7280                    this_test.status = "timeout";
7281                }
7282                GIGO.finish_test(id);
7283            }
7284        },
7285        error: function () {
7286            var delta;
7287            if (img_pending) {
7288                img_pending = 0;
7289                delta = GIGO.getms() - this_test.start_time;
7290                if (GIGO.isdef(this_test.time_ms)) {
7291                    if (delta < this_test.time_ms) {
7292                        this_test.time_ms = delta;
7293                    }
7294                } else {
7295                    this_test.time_ms = delta;
7296                }
7297                this_test.image = 1;
7298                this_test.status = (this_test.time_ms < GIGO.slow) ? "bad" : "timeout";
7299                GIGO.finish_test(id);
7300            }
7301        }
7302    });
7303
7304    // FAKE IMAGE TIMEOUT HANDLER
7305    setTimeout(function () {
7306        var delta;
7307        if (img_pending) {
7308            img_pending = 0;
7309            // replace failing image url with one that should work, so that browser can call this done.
7310            // we tried setting to "" but safari at minimum treats that as replacing src
7311            // with the value of document.location (!).
7312            jQuery(img).css("height","2em").css("width","auto");
7313            jQuery(img).attr("src", "/images/hires_bad.png");
7314
7315            delta = GIGO.getms() - this_test.start_time;
7316            if (GIGO.isdef(this_test.time_ms)) {
7317                if (delta < this_test.time_ms) {
7318                    this_test.time_ms = delta;
7319                }
7320            } else {
7321                this_test.time_ms = delta;
7322            }
7323            this_test.image = 1;
7324            this_test.status = (this_test.time_ms < GIGO.slow) ? "bad" : "timeout";
7325            GIGO.finish_test(id);
7326        }
7327    }, GIGO.max_time);
7328
7329
7330    //jQuery('body').append(img);
7331    jQuery(img).attr("src", url);
7332
7333    // Perform callback for presentation
7334    GIGO.update_url(id);
7335    GIGO.show_debug();
7336};
7337
7338
7339
7340GIGO.retest = function () {
7341    window.location.reload();
7342};
7343
7344
7345
7346GIGO.next_in_queue = function () {
7347    var fname, a;
7348    if (GIGO.queue.length > 0) {
7349        a = GIGO.queue.shift(); // Dequeue the next test.
7350        GIGO.dequeued.push(a.slice(0)); // Save a COPY.
7351        try {
7352            fname = a.shift(); // Remove first field, the function name (in the GIGO namespace).  This changes array "a".
7353        } catch (e) {
7354            alert("ERROR: GIGO.next_in_queue: not an array; value=" + a);
7355        }
7356
7357        // fname = function name
7358        // a = args array to pass.
7359        GIGO[fname].apply(GIGO, a);
7360
7361        // If we are permitted parallel execution,
7362        // set a timer to start the next job.
7363        if (!GIGO.use_queue) {
7364            setTimeout(GIGO.next_in_queue, GIGO.slowcount_delay);
7365        }
7366    }
7367    GIGO.update_progress(GIGO);
7368};
7369
7370GIGO.start_tests = function () {
7371    GIGO.browser_tweaks(GIGO); // In case we want to do tweak the document
7372    GIGO.next_in_queue(); // Get the ball rolling!
7373};
7374GIGO.restart_tests = function () {
7375    var i, l;
7376    l = GIGO.dequeued.length;
7377    for (i = 0; i < l; i = i + 1) {
7378        GIGO.queue.push(GIGO.dequeued[i]);
7379    }
7380    GIGO.update_progress(GIGO);
7381    GIGO.start_tests();
7382};
7383
7384
7385
7386GIGO.setup_tests = function () {
7387
7388    var asn_lookup_broken = 0;
7389    if (asn_lookup_broken) {
7390      jQuery('#sum_test_asn4').parent().parent().hide();
7391      jQuery('#sum_test_asn6').parent().parent().hide();
7392      jQuery('#test_asn4').parent().parent().hide();
7393      jQuery('#test_asn6').parent().parent().hide();
7394    } else {
7395      GIGO.queue.push(["test_type_json_only", GIGO.options.url.test_asn4, "test_asn4"]);
7396      GIGO.queue.push(["test_type_json_only", GIGO.options.url.test_asn6, "test_asn6"]);
7397    }
7398
7399
7400
7401
7402
7403
7404    GIGO.queue.push(["test_type_json", GIGO.options.url.test_a, "test_a"]);
7405    GIGO.queue.push(["test_type_json", GIGO.options.url.test_aaaa, "test_aaaa"]);
7406    GIGO.queue.push(["test_type_json", GIGO.options.url.test_ds, "test_ds"]);
7407
7408    GIGO.queue.push(["test_type_json", GIGO.options.url.test_v6mtu, "test_v6mtu"]);
7409    GIGO.queue.push(["test_type_json", GIGO.options.url.test_v6ns, "test_v6ns"]);
7410    GIGO.queue.push(["test_type_json", GIGO.options.url.test_dsmtu, "test_dsmtu"]);
7411    GIGO.queue.push(["test_type_img", GIGO.options.url.test_ood_img, "test_ood"]);
7412
7413
7414
7415
7416
7417    GIGO.show_debug();
7418    GIGO.prepare_fake();
7419
7420};
7421
7422GIGO.fill = function (size, str) {
7423    var s = "";
7424    while (s.length < size) {
7425        s = s + str;
7426    }
7427    s = s.substring(0, size);
7428    return s;
7429};
7430
7431
7432
7433
7434GIGO.set_default_options = function (options) {
7435
7436    options.url = (options.hasOwnProperty("url")) ? options.url : {};
7437
7438    options.domain = GIGO.mirrorconfig("site", "name", null);
7439    options.subdomain = GIGO.mirrorconfig("load", "domain", options.domain);
7440    options.ipv4 = GIGO.mirrorconfig("load", "ipv4", null);
7441    options.ipv6 = GIGO.mirrorconfig("load", "ipv6", null);
7442    options.uri = GIGO.mirrorconfig("options", "ip", "/ip/") + "?callback=?";
7443    options.img_uri = "/images-nc/bg.gif";
7444    options.img_uri_big = "/images-nc/hires_ok.png?&fill=" + GIGO.fill(1600, "x");
7445    options.img_bad_uri = "/images-nc/hires_bad.png";
7446
7447    // Determine if we can use an alternate v6mtu defined by the site config (options -> v6mtu)
7448//    options.v6mtu = GIGO.mirrorconfig("options","v6mtu","ipv6." + options.subdomain);
7449
7450
7451
7452    // options.uri = "/report-ip.php?callback=?";  // Alternative to mod_ip
7453    options.url.test_a = GIGO.protocol+"ipv4." + options.subdomain + options.uri;
7454    options.url.test_aaaa = GIGO.protocol+"ipv6." + options.subdomain + options.uri;
7455    options.url.test_ds = GIGO.protocol+"ds." + options.subdomain + options.uri;
7456
7457
7458    options.url.test_v6ns = GIGO.protocol+"ds.v6ns." + options.subdomain + options.uri;
7459    options.url.test_v6mtu = GIGO.protocol+"mtu1280." + options.subdomain + options.uri + "&size=1600&fill=" + GIGO.fill(1600, "x");
7460    options.url.test_dsmtu = GIGO.protocol+"ds." + options.subdomain + options.uri + "&size=1600&fill=" + GIGO.fill(1600, "x");
7461    options.url.test_ood=""; // Dummy
7462
7463
7464    // ASN lookups are corrently broken.
7465    options.url.test_asn4 = GIGO.protocol+"ipv4.lookup.test-ipv6.com" + options.uri + "&asn=1";
7466    options.url.test_asn6 = GIGO.protocol+"ipv6.lookup.test-ipv6.com" + options.uri + "&asn=1";
7467
7468
7469    options.url.test_a_img = GIGO.protocol+"ipv4." + options.subdomain + options.img_uri;
7470    options.url.test_aaaa_img = GIGO.protocol+"ipv6." + options.subdomain + options.img_uri;
7471    options.url.test_ds_img = GIGO.protocol+"ds." + options.subdomain + options.img_uri;
7472    options.url.test_v6ns_img = GIGO.protocol+"ds.v6ns." + options.subdomain + options.img_uri;
7473    options.url.test_v6mtu_img = GIGO.protocol+"mtu1280." + options.subdomain + options.img_uri_big;
7474    options.url.test_dsmtu_img = GIGO.protocol+"ds." + options.subdomain + options.img_uri_big;
7475    options.url.test_ood_img = GIGO.ood_url()
7476
7477
7478
7479
7480
7481};
7482
7483GIGO.fix_comment_form_and_tab = function () {
7484    if (MirrorConfig.options.comment) {
7485        jQuery("#tabbutton_mail_link").show();
7486
7487        var url = MirrorConfig.options.comment;
7488        if (MirrorConfig.options.userdata) {
7489            if (GIGO.results.ipv4.ip) {
7490                url = GIGO.protocol+"ipv4." + MirrorConfig.options.userdata + "/comment.php";
7491            } else if (GIGO.results.ipv6.ip) {
7492                url = GIGO.protocol+"ipv6." + MirrorConfig.options.userdata + "/comment.php";
7493            } else {
7494                url = GIGO.protocol+"ds." + MirrorConfig.options.userdata + "/comment.php";
7495            }
7496        }
7497
7498        $('#commentform').get(0).setAttribute('action', url);
7499
7500    } else {
7501        jQuery("#tabbutton_mail_link").hide();
7502        jQuery("a.tabbutton_mail").hide();
7503    }
7504
7505};
7506
7507
7508GIGO.test_ipv6_gui = function (options) {
7509    // Check options
7510    if (!GIGO.isdef(options)) {
7511        options = {};
7512    }
7513    GIGO.options = options;
7514    GIGO.set_default_options(options);
7515
7516
7517
7518    // Start real workload
7519    jQuery(document).ready(function () {
7520        // Primitive hack to avoid the web bots from comment spamming
7521        jQuery("[name=nobots]").val("serious");
7522        if (GIGO.is_replay()) {
7523          jQuery("#replay").show();
7524        }
7525
7526        // Possibly, kill that tab instead.
7527        // GIGO.fix_comment_form_and_tab();
7528        GIGO.fix_footer_early();
7529        GIGO.start_helpdesk();
7530        GIGO.setup_tests();
7531        GIGO.start_tests();
7532        GIGO.pulse_on();
7533    });
7534};
7535
7536GIGO.redirect = function (page) {
7537    var newurl, oldpath, newpath;
7538    newurl = document.location.protocol;
7539    newurl = newurl + "://";
7540    newurl = newurl + document.location.hostname;
7541    if (document.location.port !== 80) {
7542        newurl = newurl + ":" + document.location.port;
7543    }
7544
7545    oldpath = String(document.location.pathname);
7546    newpath = oldpath.replace(/[^\/]+$/, "");
7547    newpath = newpath + page;
7548    newpath = newpath.replace(/\/+/g, "/");
7549
7550    document.location = newpath;
7551
7552
7553};
7554
7555
7556
7557// end of base.js

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.