├── .gitignore ├── LICENSE-GPL.txt ├── LICENSE-MIT.txt ├── README.md ├── demo ├── img │ ├── 1.jpg │ ├── 10.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 6.jpg │ ├── 7.jpg │ ├── 8.jpg │ └── 9.jpg └── index.html ├── fakecrop └── jquery.fakecrop.js ├── jquery-1.7.2.min.js └── test ├── JSLitmus.js ├── qunit ├── qunit.css └── qunit.js └── test_fakecrop.html /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | -------------------------------------------------------------------------------- /LICENSE-GPL.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2012 Vuong Nguyen http://vuongnguyen.com 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . -------------------------------------------------------------------------------- /LICENSE-MIT.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Vuong Nguyen http://vuongnguyen.com 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **jQuery-Fakecrop Plugin** takes a collection of images and automatically scale them to fit a custom-defined bounding box. This creates a "fake" cropping effect on those images; which produces convincing thumbnails. 2 | 3 | For more information, please visit: http://vuongnguyen.com/fake-cropping-images-with-jquery.html 4 | 5 | **Quick Start:** 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /demo/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VuongN/jQuery-Fakecrop/c282658811b4a0a9c3ec91064952c6cfa25137ad/demo/img/1.jpg -------------------------------------------------------------------------------- /demo/img/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VuongN/jQuery-Fakecrop/c282658811b4a0a9c3ec91064952c6cfa25137ad/demo/img/10.jpg -------------------------------------------------------------------------------- /demo/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VuongN/jQuery-Fakecrop/c282658811b4a0a9c3ec91064952c6cfa25137ad/demo/img/2.jpg -------------------------------------------------------------------------------- /demo/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VuongN/jQuery-Fakecrop/c282658811b4a0a9c3ec91064952c6cfa25137ad/demo/img/3.jpg -------------------------------------------------------------------------------- /demo/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VuongN/jQuery-Fakecrop/c282658811b4a0a9c3ec91064952c6cfa25137ad/demo/img/4.jpg -------------------------------------------------------------------------------- /demo/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VuongN/jQuery-Fakecrop/c282658811b4a0a9c3ec91064952c6cfa25137ad/demo/img/5.jpg -------------------------------------------------------------------------------- /demo/img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VuongN/jQuery-Fakecrop/c282658811b4a0a9c3ec91064952c6cfa25137ad/demo/img/6.jpg -------------------------------------------------------------------------------- /demo/img/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VuongN/jQuery-Fakecrop/c282658811b4a0a9c3ec91064952c6cfa25137ad/demo/img/7.jpg -------------------------------------------------------------------------------- /demo/img/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VuongN/jQuery-Fakecrop/c282658811b4a0a9c3ec91064952c6cfa25137ad/demo/img/8.jpg -------------------------------------------------------------------------------- /demo/img/9.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VuongN/jQuery-Fakecrop/c282658811b4a0a9c3ec91064952c6cfa25137ad/demo/img/9.jpg -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jQuery-Fakecrop Sample 5 | 11 | 12 | 13 |
14 |

jQuery-Fakecrop Sample

15 |

Usage

16 |
17 |
<style>
18 | 	img { height:100px; } /** there has to be a fixed dimension width/height **/
19 | </style>
20 | 
21 | <script src="/path/to/jquery-library.js"></script>
22 | <script src="/path/to/jquery.fakecrop.js"></script>
23 | <script>
24 | 	$(document).ready(function () {
25 | 		// for a filled square thumbnail
26 | 		$('img').fakecrop();
27 | 		// for a fixed width/height
28 | 		$('img').fakecrop({fill: false});
29 | 	});
30 | </script>
31 | 			
32 |
33 |

Normal

34 |
35 | 47 |
48 |

With Fakecrop (default)

49 |
$('#fakecrop-fill img').fakecrop();
50 |
51 | 52 |
53 |

With Fakecrop {fill : false}

54 |
$('#fakecrop img').fakecrop({ fill: false });
55 |
56 | 57 |
58 | 59 |

Public domain photographs courtesy of United State Department of Agriculture

60 |
61 | 62 | 63 | 64 | 70 | 71 | -------------------------------------------------------------------------------- /fakecrop/jquery.fakecrop.js: -------------------------------------------------------------------------------- 1 | /*** 2 | * jquery.fakecrop.js 3 | * Copyright (c) 2012 Vuong Nguyen 4 | * http://vuongnguyen.com 5 | */ 6 | (function ($) { 7 | var methods = { 8 | ratio : function (args) { 9 | var item = args.item, 10 | settings = args.settings; 11 | return { w : item.width()/settings.wrapperWidth, 12 | h : item.height()/settings.wrapperHeight }; 13 | }, 14 | center : function (longVal, shortVal) { 15 | return parseInt((longVal-shortVal)/2, 10); 16 | }, 17 | scaleToFill : function (args) { 18 | var item = args.item, 19 | settings = args.settings, 20 | ratio = settings.ratio, 21 | width = item.width(), 22 | height = item.height(), 23 | offset = {top: 0, left: 0}; 24 | 25 | if (ratio.h > ratio.w) { 26 | width = settings.wrapperWidth; 27 | height = height / ratio.w; 28 | if (settings.center) { 29 | offset.top = methods.center(width, height); 30 | } 31 | } else { 32 | height = settings.wrapperHeight; 33 | width = width / ratio.h; 34 | if (settings.center) { 35 | offset.left = methods.center(height, width); 36 | } 37 | } 38 | 39 | if (settings.center) { 40 | args.wrapper.css('position', 'relative'); 41 | item.css({ 42 | 'position' : 'absolute', 43 | 'top' : ['-', offset.top, 'px'].join(''), 44 | 'left' : offset.left + 'px' 45 | }); 46 | } 47 | 48 | return item.height(height).attr('height', height + 'px') 49 | .width(width).attr('width', width + 'px'); 50 | }, 51 | scaleToFit : function (args) { 52 | var item = args.item, 53 | settings = args.settings, 54 | ratio = settings.ratio, 55 | width = item.width(), 56 | height = item.height(), 57 | offset = {top: 0, left: 0}; 58 | 59 | if (ratio.h > ratio.w) { 60 | height = settings.wrapperHeight, 61 | width = parseInt((item.width() * settings.wrapperHeight)/item.height(), 10); 62 | if (settings.center) { 63 | offset.left = methods.center(height, width); 64 | } 65 | } else { 66 | height = parseInt((item.height() * settings.wrapperWidth)/item.width(), 10), 67 | width = settings.wrapperWidth; 68 | if (settings.center) { 69 | offset.top = methods.center(width, height); 70 | } 71 | } 72 | 73 | args.wrapper.css({ 74 | 'width' : (settings.squareWidth ? settings.wrapperWidth : width) + 'px', 75 | 'height' : settings.wrapperHeight + 'px' 76 | }); 77 | 78 | if (settings.center) { 79 | args.wrapper.css('position', 'relative'); 80 | item.css({ 81 | 'position' : 'absolute', 82 | 'top' : offset.top +'px', 83 | 'left' : offset.left + 'px' 84 | }); 85 | } 86 | return item.height(height).attr('height', height + 'px') 87 | .width(width).attr('width', width + 'px'); 88 | }, 89 | init : function (options) { 90 | var settings = $.extend({ 91 | wrapperSelector : null, 92 | wrapperWidth : 100, 93 | wrapperHeight : 100, 94 | center : true, 95 | fill : true, 96 | initClass : 'fc-init', 97 | doneEvent : 'fakedropdone', 98 | squareWidth : true 99 | }, options), 100 | _init = function () { 101 | var item = $(this), 102 | wrapper = settings.wrapperSelector ? item.closest(settings.wrapperSelector) : item.parent(), 103 | args = { item : item, 104 | settings : settings, 105 | wrapper : wrapper }; 106 | settings.ratio = methods.ratio(args); 107 | if (settings.fill) { 108 | wrapper.css({ 109 | 'overflow' : 'hidden', 110 | 'width' : settings.wrapperWidth + 'px', 111 | 'height' : settings.wrapperHeight + 'px' 112 | }); 113 | methods.scaleToFill(args); 114 | } else { 115 | methods.scaleToFit(args); 116 | } 117 | 118 | item.data('fc.settings', settings) 119 | .addClass(settings.initClass) // Add class to container after initialization 120 | .trigger(settings.doneEvent); // Publish an event to announce that fakecrop in initialized 121 | }, 122 | images = this.filter('img'), 123 | others = this.filter(':not(img)'); 124 | if (images.length) { 125 | images.bind('load', function () { 126 | _init.call(this); 127 | this.style.display = 'inline'; 128 | }).each(function () { 129 | // trick from paul irish's https://gist.github.com/797120/7176db676f1e0e20d7c23933f9fc655c2f120c58 130 | if (this.complete || this.complete === undefined) { 131 | var src = this.src; 132 | this.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; 133 | this.src = src; 134 | this.style.display = 'none'; 135 | } 136 | }); 137 | } 138 | if (others.length) { 139 | others.each(_init); 140 | } 141 | return this; 142 | } 143 | }; 144 | $.fn.fakecrop = function (method) { 145 | if (methods[method]) { 146 | return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); 147 | } else if (typeof method === 'object' || !method) { 148 | return methods.init.apply(this, arguments); 149 | } else { 150 | $.error('Method ' + method + ' does not exist on jQuery.fakecrop'); 151 | } 152 | }; 153 | })(jQuery); 154 | -------------------------------------------------------------------------------- /jquery-1.7.2.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v1.7.2 jquery.com | jquery.org/license */ 2 | (function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"":"")+""),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){if(c!=="border")for(;e=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
a",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="
"+""+"
",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="
t
",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="
",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function( 3 | a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;le&&j.push({elem:this,matches:d.slice(e)});for(k=0;k0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*",""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"],col:[2,"","
"],area:[1,"",""],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div
","
"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f 4 | .clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(;d1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]===""&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window); -------------------------------------------------------------------------------- /test/JSLitmus.js: -------------------------------------------------------------------------------- 1 | // JSLitmus.js 2 | // 3 | // Copyright (c) 2010, Robert Kieffer, http://broofa.com 4 | // Available under MIT license (http://en.wikipedia.org/wiki/MIT_License) 5 | 6 | (function() { 7 | // Private methods and state 8 | 9 | // Get platform info but don't go crazy trying to recognize everything 10 | // that's out there. This is just for the major platforms and OSes. 11 | var platform = 'unknown platform', ua = navigator.userAgent; 12 | 13 | // Detect OS 14 | var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|'); 15 | var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null; 16 | if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null; 17 | 18 | // Detect browser 19 | var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null; 20 | 21 | // Detect version 22 | var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)'); 23 | var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null; 24 | var platform = (pOS && pName && pVersion) ? pName + ' ' + pVersion + ' on ' + pOS : 'unknown platform'; 25 | 26 | /** 27 | * A smattering of methods that are needed to implement the JSLitmus testbed. 28 | */ 29 | var jsl = { 30 | /** 31 | * Enhanced version of escape() 32 | */ 33 | escape: function(s) { 34 | s = s.replace(/,/g, '\\,'); 35 | s = escape(s); 36 | s = s.replace(/\+/g, '%2b'); 37 | s = s.replace(/ /g, '+'); 38 | return s; 39 | }, 40 | 41 | /** 42 | * Get an element by ID. 43 | */ 44 | $: function(id) { 45 | return document.getElementById(id); 46 | }, 47 | 48 | /** 49 | * Null function 50 | */ 51 | F: function() {}, 52 | 53 | /** 54 | * Set the status shown in the UI 55 | */ 56 | status: function(msg) { 57 | var el = jsl.$('jsl_status'); 58 | if (el) el.innerHTML = msg || ''; 59 | }, 60 | 61 | /** 62 | * Convert a number to an abbreviated string like, "15K" or "10M" 63 | */ 64 | toLabel: function(n) { 65 | if (n == Infinity) { 66 | return 'Infinity'; 67 | } else if (n > 1e9) { 68 | n = Math.round(n/1e8); 69 | return n/10 + 'B'; 70 | } else if (n > 1e6) { 71 | n = Math.round(n/1e5); 72 | return n/10 + 'M'; 73 | } else if (n > 1e3) { 74 | n = Math.round(n/1e2); 75 | return n/10 + 'K'; 76 | } 77 | return n; 78 | }, 79 | 80 | /** 81 | * Copy properties from src to dst 82 | */ 83 | extend: function(dst, src) { 84 | for (var k in src) dst[k] = src[k]; return dst; 85 | }, 86 | 87 | /** 88 | * Like Array.join(), but for the key-value pairs in an object 89 | */ 90 | join: function(o, delimit1, delimit2) { 91 | if (o.join) return o.join(delimit1); // If it's an array 92 | var pairs = []; 93 | for (var k in o) pairs.push(k + delimit1 + o[k]); 94 | return pairs.join(delimit2); 95 | }, 96 | 97 | /** 98 | * Array#indexOf isn't supported in IE, so we use this as a cross-browser solution 99 | */ 100 | indexOf: function(arr, o) { 101 | if (arr.indexOf) return arr.indexOf(o); 102 | for (var i = 0; i < this.length; i++) if (arr[i] === o) return i; 103 | return -1; 104 | } 105 | }; 106 | 107 | /** 108 | * Test manages a single test (created with 109 | * JSLitmus.test()) 110 | * 111 | * @private 112 | */ 113 | var Test = function (name, f) { 114 | if (!f) throw new Error('Undefined test function'); 115 | if (!/function[^\(]*\(([^,\)]*)/.test(f.toString())) { 116 | throw new Error('"' + name + '" test: Test is not a valid Function object'); 117 | } 118 | this.loopArg = RegExp.$1; 119 | this.name = name; 120 | this.f = f; 121 | }; 122 | 123 | jsl.extend(Test, /** @lends Test */ { 124 | /** Calibration tests for establishing iteration loop overhead */ 125 | CALIBRATIONS: [ 126 | new Test('calibrating loop', function(count) {while (count--);}), 127 | new Test('calibrating function', jsl.F) 128 | ], 129 | 130 | /** 131 | * Run calibration tests. Returns true if calibrations are not yet 132 | * complete (in which case calling code should run the tests yet again). 133 | * onCalibrated - Callback to invoke when calibrations have finished 134 | */ 135 | calibrate: function(onCalibrated) { 136 | for (var i = 0; i < Test.CALIBRATIONS.length; i++) { 137 | var cal = Test.CALIBRATIONS[i]; 138 | if (cal.running) return true; 139 | if (!cal.count) { 140 | cal.isCalibration = true; 141 | cal.onStop = onCalibrated; 142 | //cal.MIN_TIME = .1; // Do calibrations quickly 143 | cal.run(2e4); 144 | return true; 145 | } 146 | } 147 | return false; 148 | } 149 | }); 150 | 151 | jsl.extend(Test.prototype, {/** @lends Test.prototype */ 152 | /** Initial number of iterations */ 153 | INIT_COUNT: 10, 154 | /** Max iterations allowed (i.e. used to detect bad looping functions) */ 155 | MAX_COUNT: 1e9, 156 | /** Minimum time a test should take to get valid results (secs) */ 157 | MIN_TIME: .5, 158 | 159 | /** Callback invoked when test state changes */ 160 | onChange: jsl.F, 161 | 162 | /** Callback invoked when test is finished */ 163 | onStop: jsl.F, 164 | 165 | /** 166 | * Reset test state 167 | */ 168 | reset: function() { 169 | delete this.count; 170 | delete this.time; 171 | delete this.running; 172 | delete this.error; 173 | }, 174 | 175 | /** 176 | * Run the test (in a timeout). We use a timeout to make sure the browser 177 | * has a chance to finish rendering any UI changes we've made, like 178 | * updating the status message. 179 | */ 180 | run: function(count) { 181 | count = count || this.INIT_COUNT; 182 | jsl.status(this.name + ' x ' + count); 183 | this.running = true; 184 | var me = this; 185 | setTimeout(function() {me._run(count);}, 200); 186 | }, 187 | 188 | /** 189 | * The nuts and bolts code that actually runs a test 190 | */ 191 | _run: function(count) { 192 | var me = this; 193 | 194 | // Make sure calibration tests have run 195 | if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return; 196 | this.error = null; 197 | 198 | try { 199 | var start, f = this.f, now, i = count; 200 | 201 | // Start the timer 202 | start = new Date(); 203 | 204 | // Now for the money shot. If this is a looping function ... 205 | if (this.loopArg) { 206 | // ... let it do the iteration itself 207 | f(count); 208 | } else { 209 | // ... otherwise do the iteration for it 210 | while (i--) f(); 211 | } 212 | 213 | // Get time test took (in secs) 214 | this.time = Math.max(1,new Date() - start)/1000; 215 | 216 | // Store iteration count and per-operation time taken 217 | this.count = count; 218 | this.period = this.time/count; 219 | 220 | // Do we need to do another run? 221 | this.running = this.time <= this.MIN_TIME; 222 | 223 | // ... if so, compute how many times we should iterate 224 | if (this.running) { 225 | // Bump the count to the nearest power of 2 226 | var x = this.MIN_TIME/this.time; 227 | var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2)))); 228 | count *= pow; 229 | if (count > this.MAX_COUNT) { 230 | throw new Error('Max count exceeded. If this test uses a looping function, make sure the iteration loop is working properly.'); 231 | } 232 | } 233 | } catch (e) { 234 | // Exceptions are caught and displayed in the test UI 235 | this.reset(); 236 | this.error = e; 237 | } 238 | 239 | // Figure out what to do next 240 | if (this.running) { 241 | me.run(count); 242 | } else { 243 | jsl.status(''); 244 | me.onStop(me); 245 | } 246 | 247 | // Finish up 248 | this.onChange(this); 249 | }, 250 | 251 | /** 252 | * Get the number of operations per second for this test. 253 | * 254 | * @param normalize if true, iteration loop overhead taken into account 255 | */ 256 | getHz: function(/**Boolean*/ normalize) { 257 | var p = this.period; 258 | 259 | // Adjust period based on the calibration test time 260 | if (normalize && !this.isCalibration) { 261 | var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1]; 262 | 263 | // If the period is within 20% of the calibration time, then zero the 264 | // it out 265 | p = p < cal.period*1.2 ? 0 : p - cal.period; 266 | } 267 | 268 | return Math.round(1/p); 269 | }, 270 | 271 | /** 272 | * Get a friendly string describing the test 273 | */ 274 | toString: function() { 275 | return this.name + ' - ' + this.time/this.count + ' secs'; 276 | } 277 | }); 278 | 279 | // CSS we need for the UI 280 | var STYLESHEET = ''; 360 | 361 | // HTML markup for the UI 362 | var MARKUP = '
\ 363 | \ 364 | \ 365 |
\ 366 |
\ 367 | Normalize results \ 368 |
\ 369 | \ 370 | \ 371 | \ 372 | \ 373 | \ 374 | \ 375 | \ 376 | \ 377 | \ 378 | \ 379 |
' + platform + '
TestOps/sec
\ 380 |
\ 381 | \ 386 | Powered by JSLitmus \ 387 | '; 388 | 389 | /** 390 | * The public API for creating and running tests 391 | */ 392 | window.JSLitmus = { 393 | /** The list of all tests that have been registered with JSLitmus.test */ 394 | _tests: [], 395 | /** The queue of tests that need to be run */ 396 | _queue: [], 397 | 398 | /** 399 | * The parsed query parameters the current page URL. This is provided as a 400 | * convenience for test functions - it's not used by JSLitmus proper 401 | */ 402 | params: {}, 403 | 404 | /** 405 | * Initialize 406 | */ 407 | _init: function() { 408 | // Parse query params into JSLitmus.params[] hash 409 | var match = (location + '').match(/([^?#]*)(#.*)?$/); 410 | if (match) { 411 | var pairs = match[1].split('&'); 412 | for (var i = 0; i < pairs.length; i++) { 413 | var pair = pairs[i].split('='); 414 | if (pair.length > 1) { 415 | var key = pair.shift(); 416 | var value = pair.length > 1 ? pair.join('=') : pair[0]; 417 | this.params[key] = value; 418 | } 419 | } 420 | } 421 | 422 | // Write out the stylesheet. We have to do this here because IE 423 | // doesn't honor sheets written after the document has loaded. 424 | document.write(STYLESHEET); 425 | 426 | // Setup the rest of the UI once the document is loaded 427 | if (window.addEventListener) { 428 | window.addEventListener('load', this._setup, false); 429 | } else if (document.addEventListener) { 430 | document.addEventListener('load', this._setup, false); 431 | } else if (window.attachEvent) { 432 | window.attachEvent('onload', this._setup); 433 | } 434 | 435 | return this; 436 | }, 437 | 438 | /** 439 | * Set up the UI 440 | */ 441 | _setup: function() { 442 | var el = jsl.$('jslitmus_container'); 443 | if (!el) document.body.appendChild(el = document.createElement('div')); 444 | 445 | el.innerHTML = MARKUP; 446 | 447 | // Render the UI for all our tests 448 | for (var i=0; i < JSLitmus._tests.length; i++) 449 | JSLitmus.renderTest(JSLitmus._tests[i]); 450 | }, 451 | 452 | /** 453 | * (Re)render all the test results 454 | */ 455 | renderAll: function() { 456 | for (var i = 0; i < JSLitmus._tests.length; i++) 457 | JSLitmus.renderTest(JSLitmus._tests[i]); 458 | JSLitmus.renderChart(); 459 | }, 460 | 461 | /** 462 | * (Re)render the chart graphics 463 | */ 464 | renderChart: function() { 465 | var url = JSLitmus.chartUrl(); 466 | jsl.$('chart_link').href = url; 467 | jsl.$('chart_image').src = url; 468 | jsl.$('chart').style.display = ''; 469 | 470 | // Update the tiny URL 471 | jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url); 472 | }, 473 | 474 | /** 475 | * (Re)render the results for a specific test 476 | */ 477 | renderTest: function(test) { 478 | // Make a new row if needed 479 | if (!test._row) { 480 | var trow = jsl.$('test_row_template'); 481 | if (!trow) return; 482 | 483 | test._row = trow.cloneNode(true); 484 | test._row.style.display = ''; 485 | test._row.id = ''; 486 | test._row.onclick = function() {JSLitmus._queueTest(test);}; 487 | test._row.title = 'Run ' + test.name + ' test'; 488 | trow.parentNode.appendChild(test._row); 489 | test._row.cells[0].innerHTML = test.name; 490 | } 491 | 492 | var cell = test._row.cells[1]; 493 | var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping']; 494 | 495 | if (test.error) { 496 | cns.push('test_error'); 497 | cell.innerHTML = 498 | '
' + test.error + '
' + 499 | '
  • ' + 500 | jsl.join(test.error, ': ', '
  • ') + 501 | '
'; 502 | } else { 503 | if (test.running) { 504 | cns.push('test_running'); 505 | cell.innerHTML = 'running'; 506 | } else if (jsl.indexOf(JSLitmus._queue, test) >= 0) { 507 | cns.push('test_pending'); 508 | cell.innerHTML = 'pending'; 509 | } else if (test.count) { 510 | cns.push('test_done'); 511 | var hz = test.getHz(jsl.$('test_normalize').checked); 512 | cell.innerHTML = hz != Infinity ? hz : '∞'; 513 | cell.title = 'Looped ' + test.count + ' times in ' + test.time + ' seconds'; 514 | } else { 515 | cell.innerHTML = 'ready'; 516 | } 517 | } 518 | cell.className = cns.join(' '); 519 | }, 520 | 521 | /** 522 | * Create a new test 523 | */ 524 | test: function(name, f) { 525 | // Create the Test object 526 | var test = new Test(name, f); 527 | JSLitmus._tests.push(test); 528 | 529 | // Re-render if the test state changes 530 | test.onChange = JSLitmus.renderTest; 531 | 532 | // Run the next test if this one finished 533 | test.onStop = function(test) { 534 | if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test); 535 | JSLitmus.currentTest = null; 536 | JSLitmus._nextTest(); 537 | }; 538 | 539 | // Render the new test 540 | this.renderTest(test); 541 | }, 542 | 543 | /** 544 | * Add all tests to the run queue 545 | */ 546 | runAll: function(e) { 547 | e = e || window.event; 548 | var reverse = e && e.shiftKey, len = JSLitmus._tests.length; 549 | for (var i = 0; i < len; i++) { 550 | JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]); 551 | } 552 | }, 553 | 554 | /** 555 | * Remove all tests from the run queue. The current test has to finish on 556 | * it's own though 557 | */ 558 | stop: function() { 559 | while (JSLitmus._queue.length) { 560 | var test = JSLitmus._queue.shift(); 561 | JSLitmus.renderTest(test); 562 | } 563 | }, 564 | 565 | /** 566 | * Run the next test in the run queue 567 | */ 568 | _nextTest: function() { 569 | if (!JSLitmus.currentTest) { 570 | var test = JSLitmus._queue.shift(); 571 | if (test) { 572 | jsl.$('stop_button').disabled = false; 573 | JSLitmus.currentTest = test; 574 | test.run(); 575 | JSLitmus.renderTest(test); 576 | if (JSLitmus.onTestStart) JSLitmus.onTestStart(test); 577 | } else { 578 | jsl.$('stop_button').disabled = true; 579 | JSLitmus.renderChart(); 580 | } 581 | } 582 | }, 583 | 584 | /** 585 | * Add a test to the run queue 586 | */ 587 | _queueTest: function(test) { 588 | if (jsl.indexOf(JSLitmus._queue, test) >= 0) return; 589 | JSLitmus._queue.push(test); 590 | JSLitmus.renderTest(test); 591 | JSLitmus._nextTest(); 592 | }, 593 | 594 | /** 595 | * Generate a Google Chart URL that shows the data for all tests 596 | */ 597 | chartUrl: function() { 598 | var n = JSLitmus._tests.length, markers = [], data = []; 599 | var d, min = 0, max = -1e10; 600 | var normalize = jsl.$('test_normalize').checked; 601 | 602 | // Gather test data 603 | for (var i=0; i < JSLitmus._tests.length; i++) { 604 | var test = JSLitmus._tests[i]; 605 | if (test.count) { 606 | var hz = test.getHz(normalize); 607 | var v = hz != Infinity ? hz : 0; 608 | data.push(v); 609 | markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' + 610 | markers.length + ',10'); 611 | max = Math.max(v, max); 612 | } 613 | } 614 | if (markers.length <= 0) return null; 615 | 616 | // Build chart title 617 | var title = document.getElementsByTagName('title'); 618 | title = (title && title.length) ? title[0].innerHTML : null; 619 | var chart_title = []; 620 | if (title) chart_title.push(title); 621 | chart_title.push('Ops/sec (' + platform + ')'); 622 | 623 | // Build labels 624 | var labels = [jsl.toLabel(min), jsl.toLabel(max)]; 625 | 626 | var w = 250, bw = 15; 627 | var bs = 5; 628 | var h = markers.length*(bw + bs) + 30 + chart_title.length*20; 629 | 630 | var params = { 631 | chtt: escape(chart_title.join('|')), 632 | chts: '000000,10', 633 | cht: 'bhg', // chart type 634 | chd: 't:' + data.join(','), // data set 635 | chds: min + ',' + max, // max/min of data 636 | chxt: 'x', // label axes 637 | chxl: '0:|' + labels.join('|'), // labels 638 | chsp: '0,1', 639 | chm: markers.join('|'), // test names 640 | chbh: [bw, 0, bs].join(','), // bar widths 641 | // chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient 642 | chs: w + 'x' + h 643 | }; 644 | return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&'); 645 | } 646 | }; 647 | 648 | JSLitmus._init(); 649 | })(); 650 | -------------------------------------------------------------------------------- /test/qunit/qunit.css: -------------------------------------------------------------------------------- 1 | /** 2 | * QUnit - A JavaScript Unit Testing Framework 3 | * 4 | * http://docs.jquery.com/QUnit 5 | * 6 | * Copyright (c) 2011 John Resig, Jörn Zaefferer 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * or GPL (GPL-LICENSE.txt) licenses. 9 | */ 10 | 11 | /** Font Family and Sizes */ 12 | 13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; 15 | } 16 | 17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 18 | #qunit-tests { font-size: smaller; } 19 | 20 | 21 | /** Resets */ 22 | 23 | #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { 24 | margin: 0; 25 | padding: 0; 26 | } 27 | 28 | 29 | /** Header */ 30 | 31 | #qunit-header { 32 | padding: 0.5em 0 0.5em 1em; 33 | 34 | color: #8699a4; 35 | background-color: #0d3349; 36 | 37 | font-size: 1.5em; 38 | line-height: 1em; 39 | font-weight: normal; 40 | 41 | border-radius: 15px 15px 0 0; 42 | -moz-border-radius: 15px 15px 0 0; 43 | -webkit-border-top-right-radius: 15px; 44 | -webkit-border-top-left-radius: 15px; 45 | } 46 | 47 | #qunit-header a { 48 | text-decoration: none; 49 | color: #c2ccd1; 50 | } 51 | 52 | #qunit-header a:hover, 53 | #qunit-header a:focus { 54 | color: #fff; 55 | } 56 | 57 | #qunit-banner { 58 | height: 5px; 59 | } 60 | 61 | #qunit-testrunner-toolbar { 62 | padding: 0.5em 0 0.5em 2em; 63 | color: #5E740B; 64 | background-color: #eee; 65 | } 66 | 67 | #qunit-userAgent { 68 | padding: 0.5em 0 0.5em 2.5em; 69 | background-color: #2b81af; 70 | color: #fff; 71 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 72 | } 73 | 74 | 75 | /** Tests: Pass/Fail */ 76 | 77 | #qunit-tests { 78 | list-style-position: inside; 79 | } 80 | 81 | #qunit-tests li { 82 | padding: 0.4em 0.5em 0.4em 2.5em; 83 | border-bottom: 1px solid #fff; 84 | list-style-position: inside; 85 | } 86 | 87 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 88 | display: none; 89 | } 90 | 91 | #qunit-tests li strong { 92 | cursor: pointer; 93 | } 94 | 95 | #qunit-tests li a { 96 | padding: 0.5em; 97 | color: #c2ccd1; 98 | text-decoration: none; 99 | } 100 | #qunit-tests li a:hover, 101 | #qunit-tests li a:focus { 102 | color: #000; 103 | } 104 | 105 | #qunit-tests ol { 106 | margin-top: 0.5em; 107 | padding: 0.5em; 108 | 109 | background-color: #fff; 110 | 111 | border-radius: 15px; 112 | -moz-border-radius: 15px; 113 | -webkit-border-radius: 15px; 114 | 115 | box-shadow: inset 0px 2px 13px #999; 116 | -moz-box-shadow: inset 0px 2px 13px #999; 117 | -webkit-box-shadow: inset 0px 2px 13px #999; 118 | } 119 | 120 | #qunit-tests table { 121 | border-collapse: collapse; 122 | margin-top: .2em; 123 | } 124 | 125 | #qunit-tests th { 126 | text-align: right; 127 | vertical-align: top; 128 | padding: 0 .5em 0 0; 129 | } 130 | 131 | #qunit-tests td { 132 | vertical-align: top; 133 | } 134 | 135 | #qunit-tests pre { 136 | margin: 0; 137 | white-space: pre-wrap; 138 | word-wrap: break-word; 139 | } 140 | 141 | #qunit-tests del { 142 | background-color: #e0f2be; 143 | color: #374e0c; 144 | text-decoration: none; 145 | } 146 | 147 | #qunit-tests ins { 148 | background-color: #ffcaca; 149 | color: #500; 150 | text-decoration: none; 151 | } 152 | 153 | /*** Test Counts */ 154 | 155 | #qunit-tests b.counts { color: black; } 156 | #qunit-tests b.passed { color: #5E740B; } 157 | #qunit-tests b.failed { color: #710909; } 158 | 159 | #qunit-tests li li { 160 | margin: 0.5em; 161 | padding: 0.4em 0.5em 0.4em 0.5em; 162 | background-color: #fff; 163 | border-bottom: none; 164 | list-style-position: inside; 165 | } 166 | 167 | /*** Passing Styles */ 168 | 169 | #qunit-tests li li.pass { 170 | color: #5E740B; 171 | background-color: #fff; 172 | border-left: 26px solid #C6E746; 173 | } 174 | 175 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } 176 | #qunit-tests .pass .test-name { color: #366097; } 177 | 178 | #qunit-tests .pass .test-actual, 179 | #qunit-tests .pass .test-expected { color: #999999; } 180 | 181 | #qunit-banner.qunit-pass { background-color: #C6E746; } 182 | 183 | /*** Failing Styles */ 184 | 185 | #qunit-tests li li.fail { 186 | color: #710909; 187 | background-color: #fff; 188 | border-left: 26px solid #EE5757; 189 | } 190 | 191 | #qunit-tests > li:last-child { 192 | border-radius: 0 0 15px 15px; 193 | -moz-border-radius: 0 0 15px 15px; 194 | -webkit-border-bottom-right-radius: 15px; 195 | -webkit-border-bottom-left-radius: 15px; 196 | } 197 | 198 | #qunit-tests .fail { color: #000000; background-color: #EE5757; } 199 | #qunit-tests .fail .test-name, 200 | #qunit-tests .fail .module-name { color: #000000; } 201 | 202 | #qunit-tests .fail .test-actual { color: #EE5757; } 203 | #qunit-tests .fail .test-expected { color: green; } 204 | 205 | #qunit-banner.qunit-fail { background-color: #EE5757; } 206 | 207 | 208 | /** Result */ 209 | 210 | #qunit-testresult { 211 | padding: 0.5em 0.5em 0.5em 2.5em; 212 | 213 | color: #2b81af; 214 | background-color: #D2E0E6; 215 | 216 | border-bottom: 1px solid white; 217 | } 218 | 219 | /** Fixture */ 220 | 221 | #qunit-fixture { 222 | position: absolute; 223 | top: -10000px; 224 | left: -10000px; 225 | } 226 | -------------------------------------------------------------------------------- /test/qunit/qunit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * QUnit - A JavaScript Unit Testing Framework 3 | * 4 | * http://docs.jquery.com/QUnit 5 | * 6 | * Copyright (c) 2011 John Resig, Jörn Zaefferer 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * or GPL (GPL-LICENSE.txt) licenses. 9 | */ 10 | 11 | (function(window) { 12 | 13 | var defined = { 14 | setTimeout: typeof window.setTimeout !== "undefined", 15 | sessionStorage: (function() { 16 | try { 17 | return !!sessionStorage.getItem; 18 | } catch(e){ 19 | return false; 20 | } 21 | })() 22 | }; 23 | 24 | var testId = 0; 25 | 26 | var Test = function(name, testName, expected, testEnvironmentArg, async, callback) { 27 | this.name = name; 28 | this.testName = testName; 29 | this.expected = expected; 30 | this.testEnvironmentArg = testEnvironmentArg; 31 | this.async = async; 32 | this.callback = callback; 33 | this.assertions = []; 34 | }; 35 | Test.prototype = { 36 | init: function() { 37 | var tests = id("qunit-tests"); 38 | if (tests) { 39 | var b = document.createElement("strong"); 40 | b.innerHTML = "Running " + this.name; 41 | var li = document.createElement("li"); 42 | li.appendChild( b ); 43 | li.className = "running"; 44 | li.id = this.id = "test-output" + testId++; 45 | tests.appendChild( li ); 46 | } 47 | }, 48 | setup: function() { 49 | if (this.module != config.previousModule) { 50 | if ( config.previousModule ) { 51 | QUnit.moduleDone( { 52 | name: config.previousModule, 53 | failed: config.moduleStats.bad, 54 | passed: config.moduleStats.all - config.moduleStats.bad, 55 | total: config.moduleStats.all 56 | } ); 57 | } 58 | config.previousModule = this.module; 59 | config.moduleStats = { all: 0, bad: 0 }; 60 | QUnit.moduleStart( { 61 | name: this.module 62 | } ); 63 | } 64 | 65 | config.current = this; 66 | this.testEnvironment = extend({ 67 | setup: function() {}, 68 | teardown: function() {} 69 | }, this.moduleTestEnvironment); 70 | if (this.testEnvironmentArg) { 71 | extend(this.testEnvironment, this.testEnvironmentArg); 72 | } 73 | 74 | QUnit.testStart( { 75 | name: this.testName 76 | } ); 77 | 78 | // allow utility functions to access the current test environment 79 | // TODO why?? 80 | QUnit.current_testEnvironment = this.testEnvironment; 81 | 82 | try { 83 | if ( !config.pollution ) { 84 | saveGlobal(); 85 | } 86 | 87 | this.testEnvironment.setup.call(this.testEnvironment); 88 | } catch(e) { 89 | QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message ); 90 | } 91 | }, 92 | run: function() { 93 | if ( this.async ) { 94 | QUnit.stop(); 95 | } 96 | 97 | if ( config.notrycatch ) { 98 | this.callback.call(this.testEnvironment); 99 | return; 100 | } 101 | try { 102 | this.callback.call(this.testEnvironment); 103 | } catch(e) { 104 | fail("Test " + this.testName + " died, exception and test follows", e, this.callback); 105 | QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) ); 106 | // else next test will carry the responsibility 107 | saveGlobal(); 108 | 109 | // Restart the tests if they're blocking 110 | if ( config.blocking ) { 111 | start(); 112 | } 113 | } 114 | }, 115 | teardown: function() { 116 | try { 117 | checkPollution(); 118 | this.testEnvironment.teardown.call(this.testEnvironment); 119 | } catch(e) { 120 | QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message ); 121 | } 122 | }, 123 | finish: function() { 124 | if ( this.expected && this.expected != this.assertions.length ) { 125 | QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); 126 | } 127 | 128 | var good = 0, bad = 0, 129 | tests = id("qunit-tests"); 130 | 131 | config.stats.all += this.assertions.length; 132 | config.moduleStats.all += this.assertions.length; 133 | 134 | if ( tests ) { 135 | var ol = document.createElement("ol"); 136 | 137 | for ( var i = 0; i < this.assertions.length; i++ ) { 138 | var assertion = this.assertions[i]; 139 | 140 | var li = document.createElement("li"); 141 | li.className = assertion.result ? "pass" : "fail"; 142 | li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); 143 | ol.appendChild( li ); 144 | 145 | if ( assertion.result ) { 146 | good++; 147 | } else { 148 | bad++; 149 | config.stats.bad++; 150 | config.moduleStats.bad++; 151 | } 152 | } 153 | 154 | // store result when possible 155 | if ( QUnit.config.reorder && defined.sessionStorage ) { 156 | if (bad) { 157 | sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad); 158 | } else { 159 | sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName); 160 | } 161 | } 162 | 163 | if (bad == 0) { 164 | ol.style.display = "none"; 165 | } 166 | 167 | var b = document.createElement("strong"); 168 | b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; 169 | 170 | var a = document.createElement("a"); 171 | a.innerHTML = "Rerun"; 172 | a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); 173 | 174 | addEvent(b, "click", function() { 175 | var next = b.nextSibling.nextSibling, 176 | display = next.style.display; 177 | next.style.display = display === "none" ? "block" : "none"; 178 | }); 179 | 180 | addEvent(b, "dblclick", function(e) { 181 | var target = e && e.target ? e.target : window.event.srcElement; 182 | if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { 183 | target = target.parentNode; 184 | } 185 | if ( window.location && target.nodeName.toLowerCase() === "strong" ) { 186 | window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); 187 | } 188 | }); 189 | 190 | var li = id(this.id); 191 | li.className = bad ? "fail" : "pass"; 192 | li.removeChild( li.firstChild ); 193 | li.appendChild( b ); 194 | li.appendChild( a ); 195 | li.appendChild( ol ); 196 | 197 | } else { 198 | for ( var i = 0; i < this.assertions.length; i++ ) { 199 | if ( !this.assertions[i].result ) { 200 | bad++; 201 | config.stats.bad++; 202 | config.moduleStats.bad++; 203 | } 204 | } 205 | } 206 | 207 | try { 208 | QUnit.reset(); 209 | } catch(e) { 210 | fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset); 211 | } 212 | 213 | QUnit.testDone( { 214 | name: this.testName, 215 | failed: bad, 216 | passed: this.assertions.length - bad, 217 | total: this.assertions.length 218 | } ); 219 | }, 220 | 221 | queue: function() { 222 | var test = this; 223 | synchronize(function() { 224 | test.init(); 225 | }); 226 | function run() { 227 | // each of these can by async 228 | synchronize(function() { 229 | test.setup(); 230 | }); 231 | synchronize(function() { 232 | test.run(); 233 | }); 234 | synchronize(function() { 235 | test.teardown(); 236 | }); 237 | synchronize(function() { 238 | test.finish(); 239 | }); 240 | } 241 | // defer when previous test run passed, if storage is available 242 | var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName); 243 | if (bad) { 244 | run(); 245 | } else { 246 | synchronize(run); 247 | }; 248 | } 249 | 250 | }; 251 | 252 | var QUnit = { 253 | 254 | // call on start of module test to prepend name to all tests 255 | module: function(name, testEnvironment) { 256 | config.currentModule = name; 257 | config.currentModuleTestEnviroment = testEnvironment; 258 | }, 259 | 260 | asyncTest: function(testName, expected, callback) { 261 | if ( arguments.length === 2 ) { 262 | callback = expected; 263 | expected = 0; 264 | } 265 | 266 | QUnit.test(testName, expected, callback, true); 267 | }, 268 | 269 | test: function(testName, expected, callback, async) { 270 | var name = '' + testName + '', testEnvironmentArg; 271 | 272 | if ( arguments.length === 2 ) { 273 | callback = expected; 274 | expected = null; 275 | } 276 | // is 2nd argument a testEnvironment? 277 | if ( expected && typeof expected === 'object') { 278 | testEnvironmentArg = expected; 279 | expected = null; 280 | } 281 | 282 | if ( config.currentModule ) { 283 | name = '' + config.currentModule + ": " + name; 284 | } 285 | 286 | if ( !validTest(config.currentModule + ": " + testName) ) { 287 | return; 288 | } 289 | 290 | var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); 291 | test.module = config.currentModule; 292 | test.moduleTestEnvironment = config.currentModuleTestEnviroment; 293 | test.queue(); 294 | }, 295 | 296 | /** 297 | * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. 298 | */ 299 | expect: function(asserts) { 300 | config.current.expected = asserts; 301 | }, 302 | 303 | /** 304 | * Asserts true. 305 | * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); 306 | */ 307 | ok: function(a, msg) { 308 | a = !!a; 309 | var details = { 310 | result: a, 311 | message: msg 312 | }; 313 | msg = escapeHtml(msg); 314 | QUnit.log(details); 315 | config.current.assertions.push({ 316 | result: a, 317 | message: msg 318 | }); 319 | }, 320 | 321 | /** 322 | * Checks that the first two arguments are equal, with an optional message. 323 | * Prints out both actual and expected values. 324 | * 325 | * Prefered to ok( actual == expected, message ) 326 | * 327 | * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); 328 | * 329 | * @param Object actual 330 | * @param Object expected 331 | * @param String message (optional) 332 | */ 333 | equal: function(actual, expected, message) { 334 | QUnit.push(expected == actual, actual, expected, message); 335 | }, 336 | 337 | notEqual: function(actual, expected, message) { 338 | QUnit.push(expected != actual, actual, expected, message); 339 | }, 340 | 341 | deepEqual: function(actual, expected, message) { 342 | QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); 343 | }, 344 | 345 | notDeepEqual: function(actual, expected, message) { 346 | QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); 347 | }, 348 | 349 | strictEqual: function(actual, expected, message) { 350 | QUnit.push(expected === actual, actual, expected, message); 351 | }, 352 | 353 | notStrictEqual: function(actual, expected, message) { 354 | QUnit.push(expected !== actual, actual, expected, message); 355 | }, 356 | 357 | raises: function(block, expected, message) { 358 | var actual, ok = false; 359 | 360 | if (typeof expected === 'string') { 361 | message = expected; 362 | expected = null; 363 | } 364 | 365 | try { 366 | block(); 367 | } catch (e) { 368 | actual = e; 369 | } 370 | 371 | if (actual) { 372 | // we don't want to validate thrown error 373 | if (!expected) { 374 | ok = true; 375 | // expected is a regexp 376 | } else if (QUnit.objectType(expected) === "regexp") { 377 | ok = expected.test(actual); 378 | // expected is a constructor 379 | } else if (actual instanceof expected) { 380 | ok = true; 381 | // expected is a validation function which returns true is validation passed 382 | } else if (expected.call({}, actual) === true) { 383 | ok = true; 384 | } 385 | } 386 | 387 | QUnit.ok(ok, message); 388 | }, 389 | 390 | start: function() { 391 | config.semaphore--; 392 | if (config.semaphore > 0) { 393 | // don't start until equal number of stop-calls 394 | return; 395 | } 396 | if (config.semaphore < 0) { 397 | // ignore if start is called more often then stop 398 | config.semaphore = 0; 399 | } 400 | // A slight delay, to avoid any current callbacks 401 | if ( defined.setTimeout ) { 402 | window.setTimeout(function() { 403 | if ( config.timeout ) { 404 | clearTimeout(config.timeout); 405 | } 406 | 407 | config.blocking = false; 408 | process(); 409 | }, 13); 410 | } else { 411 | config.blocking = false; 412 | process(); 413 | } 414 | }, 415 | 416 | stop: function(timeout) { 417 | config.semaphore++; 418 | config.blocking = true; 419 | 420 | if ( timeout && defined.setTimeout ) { 421 | clearTimeout(config.timeout); 422 | config.timeout = window.setTimeout(function() { 423 | QUnit.ok( false, "Test timed out" ); 424 | QUnit.start(); 425 | }, timeout); 426 | } 427 | } 428 | }; 429 | 430 | // Backwards compatibility, deprecated 431 | QUnit.equals = QUnit.equal; 432 | QUnit.same = QUnit.deepEqual; 433 | 434 | // Maintain internal state 435 | var config = { 436 | // The queue of tests to run 437 | queue: [], 438 | 439 | // block until document ready 440 | blocking: true, 441 | 442 | // by default, run previously failed tests first 443 | // very useful in combination with "Hide passed tests" checked 444 | reorder: true, 445 | 446 | noglobals: false, 447 | notrycatch: false 448 | }; 449 | 450 | // Load paramaters 451 | (function() { 452 | var location = window.location || { search: "", protocol: "file:" }, 453 | params = location.search.slice( 1 ).split( "&" ), 454 | length = params.length, 455 | urlParams = {}, 456 | current; 457 | 458 | if ( params[ 0 ] ) { 459 | for ( var i = 0; i < length; i++ ) { 460 | current = params[ i ].split( "=" ); 461 | current[ 0 ] = decodeURIComponent( current[ 0 ] ); 462 | // allow just a key to turn on a flag, e.g., test.html?noglobals 463 | current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; 464 | urlParams[ current[ 0 ] ] = current[ 1 ]; 465 | if ( current[ 0 ] in config ) { 466 | config[ current[ 0 ] ] = current[ 1 ]; 467 | } 468 | } 469 | } 470 | 471 | QUnit.urlParams = urlParams; 472 | config.filter = urlParams.filter; 473 | 474 | // Figure out if we're running the tests from a server or not 475 | QUnit.isLocal = !!(location.protocol === 'file:'); 476 | })(); 477 | 478 | // Expose the API as global variables, unless an 'exports' 479 | // object exists, in that case we assume we're in CommonJS 480 | if ( typeof exports === "undefined" || typeof require === "undefined" ) { 481 | extend(window, QUnit); 482 | window.QUnit = QUnit; 483 | } else { 484 | extend(exports, QUnit); 485 | exports.QUnit = QUnit; 486 | } 487 | 488 | // define these after exposing globals to keep them in these QUnit namespace only 489 | extend(QUnit, { 490 | config: config, 491 | 492 | // Initialize the configuration options 493 | init: function() { 494 | extend(config, { 495 | stats: { all: 0, bad: 0 }, 496 | moduleStats: { all: 0, bad: 0 }, 497 | started: +new Date, 498 | updateRate: 1000, 499 | blocking: false, 500 | autostart: true, 501 | autorun: false, 502 | filter: "", 503 | queue: [], 504 | semaphore: 0 505 | }); 506 | 507 | var tests = id( "qunit-tests" ), 508 | banner = id( "qunit-banner" ), 509 | result = id( "qunit-testresult" ); 510 | 511 | if ( tests ) { 512 | tests.innerHTML = ""; 513 | } 514 | 515 | if ( banner ) { 516 | banner.className = ""; 517 | } 518 | 519 | if ( result ) { 520 | result.parentNode.removeChild( result ); 521 | } 522 | 523 | if ( tests ) { 524 | result = document.createElement( "p" ); 525 | result.id = "qunit-testresult"; 526 | result.className = "result"; 527 | tests.parentNode.insertBefore( result, tests ); 528 | result.innerHTML = 'Running...
 '; 529 | } 530 | }, 531 | 532 | /** 533 | * Resets the test setup. Useful for tests that modify the DOM. 534 | * 535 | * If jQuery is available, uses jQuery's html(), otherwise just innerHTML. 536 | */ 537 | reset: function() { 538 | if ( window.jQuery ) { 539 | jQuery( "#qunit-fixture" ).html( config.fixture ); 540 | } else { 541 | var main = id( 'qunit-fixture' ); 542 | if ( main ) { 543 | main.innerHTML = config.fixture; 544 | } 545 | } 546 | }, 547 | 548 | /** 549 | * Trigger an event on an element. 550 | * 551 | * @example triggerEvent( document.body, "click" ); 552 | * 553 | * @param DOMElement elem 554 | * @param String type 555 | */ 556 | triggerEvent: function( elem, type, event ) { 557 | if ( document.createEvent ) { 558 | event = document.createEvent("MouseEvents"); 559 | event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, 560 | 0, 0, 0, 0, 0, false, false, false, false, 0, null); 561 | elem.dispatchEvent( event ); 562 | 563 | } else if ( elem.fireEvent ) { 564 | elem.fireEvent("on"+type); 565 | } 566 | }, 567 | 568 | // Safe object type checking 569 | is: function( type, obj ) { 570 | return QUnit.objectType( obj ) == type; 571 | }, 572 | 573 | objectType: function( obj ) { 574 | if (typeof obj === "undefined") { 575 | return "undefined"; 576 | 577 | // consider: typeof null === object 578 | } 579 | if (obj === null) { 580 | return "null"; 581 | } 582 | 583 | var type = Object.prototype.toString.call( obj ) 584 | .match(/^\[object\s(.*)\]$/)[1] || ''; 585 | 586 | switch (type) { 587 | case 'Number': 588 | if (isNaN(obj)) { 589 | return "nan"; 590 | } else { 591 | return "number"; 592 | } 593 | case 'String': 594 | case 'Boolean': 595 | case 'Array': 596 | case 'Date': 597 | case 'RegExp': 598 | case 'Function': 599 | return type.toLowerCase(); 600 | } 601 | if (typeof obj === "object") { 602 | return "object"; 603 | } 604 | return undefined; 605 | }, 606 | 607 | push: function(result, actual, expected, message) { 608 | var details = { 609 | result: result, 610 | message: message, 611 | actual: actual, 612 | expected: expected 613 | }; 614 | 615 | message = escapeHtml(message) || (result ? "okay" : "failed"); 616 | message = '' + message + ""; 617 | expected = escapeHtml(QUnit.jsDump.parse(expected)); 618 | actual = escapeHtml(QUnit.jsDump.parse(actual)); 619 | var output = message + ''; 620 | if (actual != expected) { 621 | output += ''; 622 | output += ''; 623 | } 624 | if (!result) { 625 | var source = sourceFromStacktrace(); 626 | if (source) { 627 | details.source = source; 628 | output += ''; 629 | } 630 | } 631 | output += "
Expected:
' + expected + '
Result:
' + actual + '
Diff:
' + QUnit.diff(expected, actual) +'
Source:
' + source +'
"; 632 | 633 | QUnit.log(details); 634 | 635 | config.current.assertions.push({ 636 | result: !!result, 637 | message: output 638 | }); 639 | }, 640 | 641 | url: function( params ) { 642 | params = extend( extend( {}, QUnit.urlParams ), params ); 643 | var querystring = "?", 644 | key; 645 | for ( key in params ) { 646 | querystring += encodeURIComponent( key ) + "=" + 647 | encodeURIComponent( params[ key ] ) + "&"; 648 | } 649 | return window.location.pathname + querystring.slice( 0, -1 ); 650 | }, 651 | 652 | // Logging callbacks; all receive a single argument with the listed properties 653 | // run test/logs.html for any related changes 654 | begin: function() {}, 655 | // done: { failed, passed, total, runtime } 656 | done: function() {}, 657 | // log: { result, actual, expected, message } 658 | log: function() {}, 659 | // testStart: { name } 660 | testStart: function() {}, 661 | // testDone: { name, failed, passed, total } 662 | testDone: function() {}, 663 | // moduleStart: { name } 664 | moduleStart: function() {}, 665 | // moduleDone: { name, failed, passed, total } 666 | moduleDone: function() {} 667 | }); 668 | 669 | if ( typeof document === "undefined" || document.readyState === "complete" ) { 670 | config.autorun = true; 671 | } 672 | 673 | addEvent(window, "load", function() { 674 | QUnit.begin({}); 675 | 676 | // Initialize the config, saving the execution queue 677 | var oldconfig = extend({}, config); 678 | QUnit.init(); 679 | extend(config, oldconfig); 680 | 681 | config.blocking = false; 682 | 683 | var userAgent = id("qunit-userAgent"); 684 | if ( userAgent ) { 685 | userAgent.innerHTML = navigator.userAgent; 686 | } 687 | var banner = id("qunit-header"); 688 | if ( banner ) { 689 | banner.innerHTML = ' ' + banner.innerHTML + ' ' + 690 | '' + 691 | ''; 692 | addEvent( banner, "change", function( event ) { 693 | var params = {}; 694 | params[ event.target.name ] = event.target.checked ? true : undefined; 695 | window.location = QUnit.url( params ); 696 | }); 697 | } 698 | 699 | var toolbar = id("qunit-testrunner-toolbar"); 700 | if ( toolbar ) { 701 | var filter = document.createElement("input"); 702 | filter.type = "checkbox"; 703 | filter.id = "qunit-filter-pass"; 704 | addEvent( filter, "click", function() { 705 | var ol = document.getElementById("qunit-tests"); 706 | if ( filter.checked ) { 707 | ol.className = ol.className + " hidepass"; 708 | } else { 709 | var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; 710 | ol.className = tmp.replace(/ hidepass /, " "); 711 | } 712 | if ( defined.sessionStorage ) { 713 | if (filter.checked) { 714 | sessionStorage.setItem("qunit-filter-passed-tests", "true"); 715 | } else { 716 | sessionStorage.removeItem("qunit-filter-passed-tests"); 717 | } 718 | } 719 | }); 720 | if ( defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { 721 | filter.checked = true; 722 | var ol = document.getElementById("qunit-tests"); 723 | ol.className = ol.className + " hidepass"; 724 | } 725 | toolbar.appendChild( filter ); 726 | 727 | var label = document.createElement("label"); 728 | label.setAttribute("for", "qunit-filter-pass"); 729 | label.innerHTML = "Hide passed tests"; 730 | toolbar.appendChild( label ); 731 | } 732 | 733 | var main = id('qunit-fixture'); 734 | if ( main ) { 735 | config.fixture = main.innerHTML; 736 | } 737 | 738 | if (config.autostart) { 739 | QUnit.start(); 740 | } 741 | }); 742 | 743 | function done() { 744 | config.autorun = true; 745 | 746 | // Log the last module results 747 | if ( config.currentModule ) { 748 | QUnit.moduleDone( { 749 | name: config.currentModule, 750 | failed: config.moduleStats.bad, 751 | passed: config.moduleStats.all - config.moduleStats.bad, 752 | total: config.moduleStats.all 753 | } ); 754 | } 755 | 756 | var banner = id("qunit-banner"), 757 | tests = id("qunit-tests"), 758 | runtime = +new Date - config.started, 759 | passed = config.stats.all - config.stats.bad, 760 | html = [ 761 | 'Tests completed in ', 762 | runtime, 763 | ' milliseconds.
', 764 | '', 765 | passed, 766 | ' tests of ', 767 | config.stats.all, 768 | ' passed, ', 769 | config.stats.bad, 770 | ' failed.' 771 | ].join(''); 772 | 773 | if ( banner ) { 774 | banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); 775 | } 776 | 777 | if ( tests ) { 778 | id( "qunit-testresult" ).innerHTML = html; 779 | } 780 | 781 | QUnit.done( { 782 | failed: config.stats.bad, 783 | passed: passed, 784 | total: config.stats.all, 785 | runtime: runtime 786 | } ); 787 | } 788 | 789 | function validTest( name ) { 790 | var filter = config.filter, 791 | run = false; 792 | 793 | if ( !filter ) { 794 | return true; 795 | } 796 | 797 | not = filter.charAt( 0 ) === "!"; 798 | if ( not ) { 799 | filter = filter.slice( 1 ); 800 | } 801 | 802 | if ( name.indexOf( filter ) !== -1 ) { 803 | return !not; 804 | } 805 | 806 | if ( not ) { 807 | run = true; 808 | } 809 | 810 | return run; 811 | } 812 | 813 | // so far supports only Firefox, Chrome and Opera (buggy) 814 | // could be extended in the future to use something like https://github.com/csnover/TraceKit 815 | function sourceFromStacktrace() { 816 | try { 817 | throw new Error(); 818 | } catch ( e ) { 819 | if (e.stacktrace) { 820 | // Opera 821 | return e.stacktrace.split("\n")[6]; 822 | } else if (e.stack) { 823 | // Firefox, Chrome 824 | return e.stack.split("\n")[4]; 825 | } 826 | } 827 | } 828 | 829 | function escapeHtml(s) { 830 | if (!s) { 831 | return ""; 832 | } 833 | s = s + ""; 834 | return s.replace(/[\&"<>\\]/g, function(s) { 835 | switch(s) { 836 | case "&": return "&"; 837 | case "\\": return "\\\\"; 838 | case '"': return '\"'; 839 | case "<": return "<"; 840 | case ">": return ">"; 841 | default: return s; 842 | } 843 | }); 844 | } 845 | 846 | function synchronize( callback ) { 847 | config.queue.push( callback ); 848 | 849 | if ( config.autorun && !config.blocking ) { 850 | process(); 851 | } 852 | } 853 | 854 | function process() { 855 | var start = (new Date()).getTime(); 856 | 857 | while ( config.queue.length && !config.blocking ) { 858 | if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) { 859 | config.queue.shift()(); 860 | } else { 861 | window.setTimeout( process, 13 ); 862 | break; 863 | } 864 | } 865 | if (!config.blocking && !config.queue.length) { 866 | done(); 867 | } 868 | } 869 | 870 | function saveGlobal() { 871 | config.pollution = []; 872 | 873 | if ( config.noglobals ) { 874 | for ( var key in window ) { 875 | config.pollution.push( key ); 876 | } 877 | } 878 | } 879 | 880 | function checkPollution( name ) { 881 | var old = config.pollution; 882 | saveGlobal(); 883 | 884 | var newGlobals = diff( config.pollution, old ); 885 | if ( newGlobals.length > 0 ) { 886 | ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); 887 | } 888 | 889 | var deletedGlobals = diff( old, config.pollution ); 890 | if ( deletedGlobals.length > 0 ) { 891 | ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); 892 | } 893 | } 894 | 895 | // returns a new Array with the elements that are in a but not in b 896 | function diff( a, b ) { 897 | var result = a.slice(); 898 | for ( var i = 0; i < result.length; i++ ) { 899 | for ( var j = 0; j < b.length; j++ ) { 900 | if ( result[i] === b[j] ) { 901 | result.splice(i, 1); 902 | i--; 903 | break; 904 | } 905 | } 906 | } 907 | return result; 908 | } 909 | 910 | function fail(message, exception, callback) { 911 | if ( typeof console !== "undefined" && console.error && console.warn ) { 912 | console.error(message); 913 | console.error(exception); 914 | console.warn(callback.toString()); 915 | 916 | } else if ( window.opera && opera.postError ) { 917 | opera.postError(message, exception, callback.toString); 918 | } 919 | } 920 | 921 | function extend(a, b) { 922 | for ( var prop in b ) { 923 | if ( b[prop] === undefined ) { 924 | delete a[prop]; 925 | } else { 926 | a[prop] = b[prop]; 927 | } 928 | } 929 | 930 | return a; 931 | } 932 | 933 | function addEvent(elem, type, fn) { 934 | if ( elem.addEventListener ) { 935 | elem.addEventListener( type, fn, false ); 936 | } else if ( elem.attachEvent ) { 937 | elem.attachEvent( "on" + type, fn ); 938 | } else { 939 | fn(); 940 | } 941 | } 942 | 943 | function id(name) { 944 | return !!(typeof document !== "undefined" && document && document.getElementById) && 945 | document.getElementById( name ); 946 | } 947 | 948 | // Test for equality any JavaScript type. 949 | // Discussions and reference: http://philrathe.com/articles/equiv 950 | // Test suites: http://philrathe.com/tests/equiv 951 | // Author: Philippe Rathé 952 | QUnit.equiv = function () { 953 | 954 | var innerEquiv; // the real equiv function 955 | var callers = []; // stack to decide between skip/abort functions 956 | var parents = []; // stack to avoiding loops from circular referencing 957 | 958 | // Call the o related callback with the given arguments. 959 | function bindCallbacks(o, callbacks, args) { 960 | var prop = QUnit.objectType(o); 961 | if (prop) { 962 | if (QUnit.objectType(callbacks[prop]) === "function") { 963 | return callbacks[prop].apply(callbacks, args); 964 | } else { 965 | return callbacks[prop]; // or undefined 966 | } 967 | } 968 | } 969 | 970 | var callbacks = function () { 971 | 972 | // for string, boolean, number and null 973 | function useStrictEquality(b, a) { 974 | if (b instanceof a.constructor || a instanceof b.constructor) { 975 | // to catch short annotaion VS 'new' annotation of a declaration 976 | // e.g. var i = 1; 977 | // var j = new Number(1); 978 | return a == b; 979 | } else { 980 | return a === b; 981 | } 982 | } 983 | 984 | return { 985 | "string": useStrictEquality, 986 | "boolean": useStrictEquality, 987 | "number": useStrictEquality, 988 | "null": useStrictEquality, 989 | "undefined": useStrictEquality, 990 | 991 | "nan": function (b) { 992 | return isNaN(b); 993 | }, 994 | 995 | "date": function (b, a) { 996 | return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf(); 997 | }, 998 | 999 | "regexp": function (b, a) { 1000 | return QUnit.objectType(b) === "regexp" && 1001 | a.source === b.source && // the regex itself 1002 | a.global === b.global && // and its modifers (gmi) ... 1003 | a.ignoreCase === b.ignoreCase && 1004 | a.multiline === b.multiline; 1005 | }, 1006 | 1007 | // - skip when the property is a method of an instance (OOP) 1008 | // - abort otherwise, 1009 | // initial === would have catch identical references anyway 1010 | "function": function () { 1011 | var caller = callers[callers.length - 1]; 1012 | return caller !== Object && 1013 | typeof caller !== "undefined"; 1014 | }, 1015 | 1016 | "array": function (b, a) { 1017 | var i, j, loop; 1018 | var len; 1019 | 1020 | // b could be an object literal here 1021 | if ( ! (QUnit.objectType(b) === "array")) { 1022 | return false; 1023 | } 1024 | 1025 | len = a.length; 1026 | if (len !== b.length) { // safe and faster 1027 | return false; 1028 | } 1029 | 1030 | //track reference to avoid circular references 1031 | parents.push(a); 1032 | for (i = 0; i < len; i++) { 1033 | loop = false; 1034 | for(j=0;j= 0) { 1179 | type = "array"; 1180 | } else { 1181 | type = typeof obj; 1182 | } 1183 | return type; 1184 | }, 1185 | separator:function() { 1186 | return this.multiline ? this.HTML ? '
' : '\n' : this.HTML ? ' ' : ' '; 1187 | }, 1188 | indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing 1189 | if ( !this.multiline ) 1190 | return ''; 1191 | var chr = this.indentChar; 1192 | if ( this.HTML ) 1193 | chr = chr.replace(/\t/g,' ').replace(/ /g,' '); 1194 | return Array( this._depth_ + (extra||0) ).join(chr); 1195 | }, 1196 | up:function( a ) { 1197 | this._depth_ += a || 1; 1198 | }, 1199 | down:function( a ) { 1200 | this._depth_ -= a || 1; 1201 | }, 1202 | setParser:function( name, parser ) { 1203 | this.parsers[name] = parser; 1204 | }, 1205 | // The next 3 are exposed so you can use them 1206 | quote:quote, 1207 | literal:literal, 1208 | join:join, 1209 | // 1210 | _depth_: 1, 1211 | // This is the list of parsers, to modify them, use jsDump.setParser 1212 | parsers:{ 1213 | window: '[Window]', 1214 | document: '[Document]', 1215 | error:'[ERROR]', //when no parser is found, shouldn't happen 1216 | unknown: '[Unknown]', 1217 | 'null':'null', 1218 | 'undefined':'undefined', 1219 | 'function':function( fn ) { 1220 | var ret = 'function', 1221 | name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE 1222 | if ( name ) 1223 | ret += ' ' + name; 1224 | ret += '('; 1225 | 1226 | ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); 1227 | return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); 1228 | }, 1229 | array: array, 1230 | nodelist: array, 1231 | arguments: array, 1232 | object:function( map ) { 1233 | var ret = [ ]; 1234 | QUnit.jsDump.up(); 1235 | for ( var key in map ) 1236 | ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(map[key]) ); 1237 | QUnit.jsDump.down(); 1238 | return join( '{', ret, '}' ); 1239 | }, 1240 | node:function( node ) { 1241 | var open = QUnit.jsDump.HTML ? '<' : '<', 1242 | close = QUnit.jsDump.HTML ? '>' : '>'; 1243 | 1244 | var tag = node.nodeName.toLowerCase(), 1245 | ret = open + tag; 1246 | 1247 | for ( var a in QUnit.jsDump.DOMAttrs ) { 1248 | var val = node[QUnit.jsDump.DOMAttrs[a]]; 1249 | if ( val ) 1250 | ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); 1251 | } 1252 | return ret + close + open + '/' + tag + close; 1253 | }, 1254 | functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function 1255 | var l = fn.length; 1256 | if ( !l ) return ''; 1257 | 1258 | var args = Array(l); 1259 | while ( l-- ) 1260 | args[l] = String.fromCharCode(97+l);//97 is 'a' 1261 | return ' ' + args.join(', ') + ' '; 1262 | }, 1263 | key:quote, //object calls it internally, the key part of an item in a map 1264 | functionCode:'[code]', //function calls it internally, it's the content of the function 1265 | attribute:quote, //node calls it internally, it's an html attribute value 1266 | string:quote, 1267 | date:quote, 1268 | regexp:literal, //regex 1269 | number:literal, 1270 | 'boolean':literal 1271 | }, 1272 | DOMAttrs:{//attributes to dump from nodes, name=>realName 1273 | id:'id', 1274 | name:'name', 1275 | 'class':'className' 1276 | }, 1277 | HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) 1278 | indentChar:' ',//indentation unit 1279 | multiline:true //if true, items in a collection, are separated by a \n, else just a space. 1280 | }; 1281 | 1282 | return jsDump; 1283 | })(); 1284 | 1285 | // from Sizzle.js 1286 | function getText( elems ) { 1287 | var ret = "", elem; 1288 | 1289 | for ( var i = 0; elems[i]; i++ ) { 1290 | elem = elems[i]; 1291 | 1292 | // Get the text from text nodes and CDATA nodes 1293 | if ( elem.nodeType === 3 || elem.nodeType === 4 ) { 1294 | ret += elem.nodeValue; 1295 | 1296 | // Traverse everything else, except comment nodes 1297 | } else if ( elem.nodeType !== 8 ) { 1298 | ret += getText( elem.childNodes ); 1299 | } 1300 | } 1301 | 1302 | return ret; 1303 | }; 1304 | 1305 | /* 1306 | * Javascript Diff Algorithm 1307 | * By John Resig (http://ejohn.org/) 1308 | * Modified by Chu Alan "sprite" 1309 | * 1310 | * Released under the MIT license. 1311 | * 1312 | * More Info: 1313 | * http://ejohn.org/projects/javascript-diff-algorithm/ 1314 | * 1315 | * Usage: QUnit.diff(expected, actual) 1316 | * 1317 | * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" 1318 | */ 1319 | QUnit.diff = (function() { 1320 | function diff(o, n){ 1321 | var ns = new Object(); 1322 | var os = new Object(); 1323 | 1324 | for (var i = 0; i < n.length; i++) { 1325 | if (ns[n[i]] == null) 1326 | ns[n[i]] = { 1327 | rows: new Array(), 1328 | o: null 1329 | }; 1330 | ns[n[i]].rows.push(i); 1331 | } 1332 | 1333 | for (var i = 0; i < o.length; i++) { 1334 | if (os[o[i]] == null) 1335 | os[o[i]] = { 1336 | rows: new Array(), 1337 | n: null 1338 | }; 1339 | os[o[i]].rows.push(i); 1340 | } 1341 | 1342 | for (var i in ns) { 1343 | if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { 1344 | n[ns[i].rows[0]] = { 1345 | text: n[ns[i].rows[0]], 1346 | row: os[i].rows[0] 1347 | }; 1348 | o[os[i].rows[0]] = { 1349 | text: o[os[i].rows[0]], 1350 | row: ns[i].rows[0] 1351 | }; 1352 | } 1353 | } 1354 | 1355 | for (var i = 0; i < n.length - 1; i++) { 1356 | if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && 1357 | n[i + 1] == o[n[i].row + 1]) { 1358 | n[i + 1] = { 1359 | text: n[i + 1], 1360 | row: n[i].row + 1 1361 | }; 1362 | o[n[i].row + 1] = { 1363 | text: o[n[i].row + 1], 1364 | row: i + 1 1365 | }; 1366 | } 1367 | } 1368 | 1369 | for (var i = n.length - 1; i > 0; i--) { 1370 | if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && 1371 | n[i - 1] == o[n[i].row - 1]) { 1372 | n[i - 1] = { 1373 | text: n[i - 1], 1374 | row: n[i].row - 1 1375 | }; 1376 | o[n[i].row - 1] = { 1377 | text: o[n[i].row - 1], 1378 | row: i - 1 1379 | }; 1380 | } 1381 | } 1382 | 1383 | return { 1384 | o: o, 1385 | n: n 1386 | }; 1387 | } 1388 | 1389 | return function(o, n){ 1390 | o = o.replace(/\s+$/, ''); 1391 | n = n.replace(/\s+$/, ''); 1392 | var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); 1393 | 1394 | var str = ""; 1395 | 1396 | var oSpace = o.match(/\s+/g); 1397 | if (oSpace == null) { 1398 | oSpace = [" "]; 1399 | } 1400 | else { 1401 | oSpace.push(" "); 1402 | } 1403 | var nSpace = n.match(/\s+/g); 1404 | if (nSpace == null) { 1405 | nSpace = [" "]; 1406 | } 1407 | else { 1408 | nSpace.push(" "); 1409 | } 1410 | 1411 | if (out.n.length == 0) { 1412 | for (var i = 0; i < out.o.length; i++) { 1413 | str += '' + out.o[i] + oSpace[i] + ""; 1414 | } 1415 | } 1416 | else { 1417 | if (out.n[0].text == null) { 1418 | for (n = 0; n < out.o.length && out.o[n].text == null; n++) { 1419 | str += '' + out.o[n] + oSpace[n] + ""; 1420 | } 1421 | } 1422 | 1423 | for (var i = 0; i < out.n.length; i++) { 1424 | if (out.n[i].text == null) { 1425 | str += '' + out.n[i] + nSpace[i] + ""; 1426 | } 1427 | else { 1428 | var pre = ""; 1429 | 1430 | for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { 1431 | pre += '' + out.o[n] + oSpace[n] + ""; 1432 | } 1433 | str += " " + out.n[i].text + nSpace[i] + pre; 1434 | } 1435 | } 1436 | } 1437 | 1438 | return str; 1439 | }; 1440 | })(); 1441 | 1442 | })(this); 1443 | -------------------------------------------------------------------------------- /test/test_fakecrop.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Fakecrop Tests 5 | 6 | 7 | 8 |

Fakecrop Tests

9 |

10 |
11 |

12 |
    13 |
    14 | 19 |
    20 |
    21 |
    22 |
    23 |
    24 |
    25 |
    26 |
    27 |
    28 |
    29 |
    30 |
    31 |
    32 |
    33 |
    34 |
    35 |
    36 |
    37 |
    38 |
    39 |
    40 |
    41 |
    42 |
    43 |
    44 | 45 | 46 | 47 | 48 | 105 | 106 | 107 | --------------------------------------------------------------------------------