├── test ├── longcomment.html ├── money.html ├── happy.html ├── test.js ├── index2.html ├── test2.js ├── index.html ├── qunit.css ├── qunit.js └── jquery-1.6.4.min.js ├── pebbles.js └── README /test/longcomment.html: -------------------------------------------------------------------------------- 1 |

Long comment...

2 | 3 |

...

4 | 5 |

...

6 | 7 | -------------------------------------------------------------------------------- /test/money.html: -------------------------------------------------------------------------------- 1 |
 2 |         $
 3 |      ,$$$$$,
 4 |    ,$$$'$`$$$
 5 |    $$$  $   `
 6 |    '$$$,$
 7 |      '$$$$,
 8 |        '$$$$,
 9 |         $ $$$,
10 |     ,   $  $$$
11 |     $$$,$.$$$'
12 |      '$$$$$'
13 |         $
14 | 
15 | -------------------------------------------------------------------------------- /test/happy.html: -------------------------------------------------------------------------------- 1 |

Pellentesque nibh felis, eleifend id, commodo in, interdum vitae, leo. Praesent eu elit. Ut eu ligula. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Maecenas elementum augue nec nisl. Proin auctor lorem at nibh. Curabitur nulla purus, feugiat id, elementum in, lobortis quis, pede. Vivamus sodales adipiscing sapien. Vestibulum posuere nulla eget wisi. Integer volutpat ligula eget enim. Suspendisse vitae arcu. Quisque pellentesque. Nullam consequat, sem vitae rhoncus tristique, mauris nulla fermentum est, bibendum ullamcorper sapien magna et quam. Sed dapibus vehicula odio. Proin bibendum gravida nisl. Fusce lorem. Phasellus sagittis, nulla in hendrerit laoreet, libero lacus feugiat urna, eget hendrerit pede magna vitae lorem. Praesent mauris.

2 | 3 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | module('open-close'); 2 | 3 | asyncTest('open', 6, function () { 4 | var button = $('.open-close .actionable'); 5 | 6 | ok($('#long-comment').html() === '', '#long-comment div starts empty'); 7 | 8 | button.click(); 9 | 10 | ok(button.find('.when-open').is(':visible'), '.when-open was shown'); 11 | ok(!button.find('.when-closed').is(':visible'), '.when-closed was hidden'); 12 | 13 | ok($('#long-comment img').length === 1, 'spinner image was added to #long-comment'); 14 | 15 | // Wait while it loads the contents for the div. 16 | pebbles.utils.wait(100, function () { 17 | ok($('#long-comment').children('img').length === 0, 'spinner was removed when comment loaded'); 18 | ok($('#long-comment').children('p').length === 3, '#long-comment div loaded html

'); 19 | 20 | start(); 21 | }); 22 | }); 23 | 24 | 25 | module('submit-form'); 26 | 27 | asyncTest('submit', 3, function () { 28 | var button = $('.submit-form .actionable'); 29 | 30 | ok($('#sethappy').children().length === 1, '#sethappy div only contains the button'); 31 | 32 | button.click(); 33 | 34 | pebbles.utils.wait(100, function () { 35 | ok($('#sethappy').children('.actionable').length === 0, '.actionable button was replaced'); 36 | ok($('#sethappy').children('p').length === 1, '#sethappy div contents were replaced correctly'); 37 | 38 | start(); 39 | }); 40 | }); 41 | 42 | 43 | module('replace'); 44 | 45 | asyncTest('replace', 3, function () { 46 | var button = $('.replace .actionable'); 47 | 48 | ok($('#money').children().length === 1, '#money div only contains the button'); 49 | 50 | button.click(); 51 | 52 | pebbles.utils.wait(100, function () { 53 | ok($('#money').children('.actionable').length === 0, '.actionable button was replaced'); 54 | ok($('#money').children('pre').length === 1, '#money div contents were replaced correctly'); 55 | 56 | start(); 57 | }); 58 | }); 59 | 60 | 61 | -------------------------------------------------------------------------------- /test/index2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |      5 |     pebbles 6 |      7 | 8 |   9 | 10 |

pebbles

11 |

12 |
13 |

14 |
    15 |
    16 |
    17 |
    18 |
    show full comment
    19 |
    hide
    20 |
    21 | 22 |
    23 | 24 |
    25 |
    26 | 34 |
    35 |
    36 | 37 |
    38 |
    39 | 42 |
    43 |
    44 |
    45 | 46 |      47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /test/test2.js: -------------------------------------------------------------------------------- 1 | module('open-close'); 2 | 3 | asyncTest('open', 6, function () { 4 | var button = $('.open-close [data-pebbles-actionable]'); 5 | 6 | ok($('#long-comment').html() === '', '#long-comment div starts empty'); 7 | 8 | button.click(); 9 | 10 | ok(button.find('.when-open').is(':visible'), '.when-open was shown'); 11 | ok(!button.find('.when-closed').is(':visible'), '.when-closed was hidden'); 12 | 13 | ok($('#long-comment img').length === 1, 'spinner image was added to #long-comment'); 14 | 15 | // Wait while it loads the contents for the div. 16 | pebbles.utils.wait(100, function () { 17 | ok($('#long-comment').children('img').length === 0, 'spinner was removed when comment loaded'); 18 | ok($('#long-comment').children('p').length === 3, '#long-comment div loaded html

    '); 19 | 20 | start(); 21 | }); 22 | }); 23 | 24 | 25 | module('submit-form'); 26 | 27 | asyncTest('submit', 3, function () { 28 | var button = $('.submit-form [data-pebbles-actionable]'); 29 | 30 | ok($('#sethappy').children().length === 1, '#sethappy div only contains the button'); 31 | 32 | button.click(); 33 | 34 | pebbles.utils.wait(100, function () { 35 | ok($('#sethappy').children('[data-pebbles-actionable]').length === 0, '[data-pebbles-actionable] button was replaced'); 36 | ok($('#sethappy').children('p').length === 1, '#sethappy div contents were replaced correctly'); 37 | 38 | start(); 39 | }); 40 | }); 41 | 42 | 43 | module('replace'); 44 | 45 | asyncTest('replace', 3, function () { 46 | var button = $('.replace [data-pebbles-actionable]'); 47 | 48 | ok($('#money').children().length === 1, '#money div only contains the button'); 49 | 50 | button.click(); 51 | 52 | pebbles.utils.wait(100, function () { 53 | ok($('#money').children('[data-pebbles-actionable]').length === 0, '[data-pebbles-actionable] button was replaced'); 54 | ok($('#money').children('pre').length === 1, '#money div contents were replaced correctly'); 55 | 56 | start(); 57 | }); 58 | }); 59 | 60 | 61 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |      5 |     pebbles 6 |      7 | 8 |   9 | 10 |

    pebbles

    11 |

    12 |
    13 |

    14 |
      15 |
      16 |
      17 |
      18 |
      show full comment
      19 |
      hide
      20 |
      21 | 22 | 23 | 24 |
      25 |
      26 | 27 |
      28 | 29 |
      30 |
      31 | 45 |
      46 |
      47 | 48 |
      49 |
      50 | 59 |
      60 |
      61 |
      62 | 63 |      64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /test/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, sans-serif; 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 | white-space: pre; 190 | } 191 | 192 | #qunit-tests > li:last-child { 193 | border-radius: 0 0 15px 15px; 194 | -moz-border-radius: 0 0 15px 15px; 195 | -webkit-border-bottom-right-radius: 15px; 196 | -webkit-border-bottom-left-radius: 15px; 197 | } 198 | 199 | #qunit-tests .fail { color: #000000; background-color: #EE5757; } 200 | #qunit-tests .fail .test-name, 201 | #qunit-tests .fail .module-name { color: #000000; } 202 | 203 | #qunit-tests .fail .test-actual { color: #EE5757; } 204 | #qunit-tests .fail .test-expected { color: green; } 205 | 206 | #qunit-banner.qunit-fail { background-color: #EE5757; } 207 | 208 | 209 | /** Result */ 210 | 211 | #qunit-testresult { 212 | padding: 0.5em 0.5em 0.5em 2.5em; 213 | 214 | color: #2b81af; 215 | background-color: #D2E0E6; 216 | 217 | border-bottom: 1px solid white; 218 | } 219 | 220 | /** Fixture */ 221 | 222 | #qunit-fixture { 223 | position: absolute; 224 | top: -10000px; 225 | left: -10000px; 226 | } 227 | -------------------------------------------------------------------------------- /pebbles.js: -------------------------------------------------------------------------------- 1 | pebbles = {}; 2 | 3 | pebbles.utils = function() { 4 | var wait = function(time, f) { 5 | setTimeout(f, time); 6 | }; 7 | 8 | var assert = function(bool, message) { 9 | if(!bool) { 10 | if(message) { 11 | throw message; 12 | } else { 13 | throw 'Assertion failed'; 14 | } 15 | } 16 | }; 17 | 18 | return { 19 | wait : wait, 20 | assert : assert, 21 | flush : function(f) { wait(1, f); } 22 | }; 23 | }(); 24 | 25 | 26 | /* 27 | Docs at http://www.jperla.com/blog/write-bug-free-javascript-with-pebbles 28 | 29 | */ 30 | 31 | 32 | pebbles.ajax = function(spinner) { 33 | // Put the spinner url in the pebbles object so we can get it in our handlers 34 | pebbles.spinner = spinner; 35 | 36 | var kwargs_of_action = function(button) { 37 | var kwargs = {}; 38 | 39 | //HTML 5 data attributes 40 | if(button.is('[data-pebbles-actionable]')) { 41 | var data = button.data(); 42 | 43 | for(var k in data) { 44 | if(k.indexOf('pebbles') === 0 && k !== 'pebblesActionable') { 45 | kwargs[k.substr(7).toLowerCase()] = data[k]; 46 | } 47 | } 48 | } else { 49 | var inputs = button.children('.kwargs').children('input'); 50 | 51 | for(var i=0;i 1) { 83 | throw 'Too many targets found for selector: ' + kwargs['target-type'] + kwargs['target']; 84 | } else { 85 | return target; 86 | } 87 | }; 88 | 89 | var action = function(e) { 90 | var button = jQuery(this); 91 | var kwargs = kwargs_of_action(button); 92 | 93 | if(pebbles.handlers.hasOwnProperty(kwargs['type'])) { 94 | return pebbles.handlers[kwargs['type']](button, kwargs); 95 | } else { 96 | throw 'No known kwargs type'; 97 | } 98 | }; 99 | 100 | return { 101 | action: action, 102 | target_from_kwargs: target_from_kwargs 103 | }; 104 | }(); 105 | 106 | pebbles.handlers = function () { 107 | var generate_replace_and_show = function(target) { 108 | var replace_and_show = function(response) { 109 | target.html(response); 110 | target.show(); 111 | }; 112 | return replace_and_show; 113 | }; 114 | 115 | var act_on_opener_closer = function(button, kwargs) { 116 | var target = pebbles.ajax.target_from_kwargs(button, kwargs); 117 | if(target.css('display') != 'none') { 118 | button.children('.when-closed').show(); 119 | button.children('.when-open').hide(); 120 | target.hide(); 121 | } else { 122 | var url = kwargs['url']; 123 | button.children('.when-closed').hide(); 124 | button.children('.when-open').show(); 125 | if(target.html() != "" || !url) { 126 | target.show(); 127 | } else { 128 | target.html(''); 129 | target.show(); 130 | pebbles.utils.flush(function() { 131 | jQuery.ajax({url: url, 132 | success: generate_replace_and_show(target) }); 133 | }); 134 | } 135 | } 136 | return false; 137 | }; 138 | 139 | var act_on_form_submitter = function(button, kwargs) { 140 | var target = pebbles.ajax.target_from_kwargs(button, kwargs); 141 | if(kwargs['form']) { 142 | var form = jQuery(kwargs['form']); 143 | } else { 144 | var form = button.find('form'); 145 | } 146 | pebbles.utils.assert(form.length == 1, 'No form found in button'); 147 | var method = form.attr('method'); 148 | var url = form.attr('action'); 149 | pebbles.utils.assert(url !== '', 'Form submit URL is not blank'); 150 | var data = form.serialize(); 151 | pebbles.utils.assert(data !== '', 'Form should send some data'); 152 | button.html(''); 153 | jQuery.ajax({url: url, 154 | method: method, 155 | data: data, 156 | success: generate_replace_and_show(target) }); 157 | return false; 158 | }; 159 | 160 | var always_replace_target_with_url = function(button, kwargs) { 161 | var target = pebbles.ajax.target_from_kwargs(button, kwargs); 162 | 163 | target.hide(); 164 | pebbles.utils.flush(function() { 165 | jQuery.ajax({url: kwargs['url'], 166 | success: generate_replace_and_show(target) }); 167 | }); 168 | return false; 169 | }; 170 | 171 | return { 172 | 'open-close': act_on_opener_closer, 173 | 'submit-form': act_on_form_submitter, 174 | 'replace': always_replace_target_with_url 175 | }; 176 | }(); 177 | 178 | 179 | jQuery(function() { 180 | jQuery(this).delegate('.actionable, [data-pebbles-actionable]', 'click', pebbles.ajax.action); 181 | }); 182 | 183 | 184 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Docs at http://www.jperla.com/blog/post/write-bug-free-javascript-with-pebbles 2 | 3 | Goals of Pebbles: 4 | * so easy that a designer could write complicated AJAX! 5 | * 0 lines of javascript 6 | * complicated ajax websites 7 | * 0 lines of javascript 8 | * no bugs 9 | * 0 lines of javascript 10 | * very fast speed and optimality. 11 | * backwards compatibility with clients who have javascript off (this was more important 4 years ago when I first made this) 12 | 13 | Plus, you don't even have to write one line of javascript! 14 | 15 | The basic idea is that almost every complicated AJAX interaction can be reduced to a handful of fundamental actions which can be composed (remind you of UNIX?). So, all a programmer has to do with this library is add few lines of HTML to elements of a page to describe the Pebbles response that happens when someone clicks that element. Maybe you submit a form, maybe you fetch some content and update part of the page. 16 | 17 | Most current website write and rewrite slightly different versions of these same basic patterns in javascript. This separates the HTML which has information about AJAX interactions and the Javascript which has other information. 18 | 19 | Javascript can be tricky to write even for an experience programmer. Moreover, a lot of this stuff is repeated, and it shouldn't be. Pebbles brings more of a descriptive style programming (a la Haskell, Prolog) to the web in the simplest of ways. 20 | 21 | 22 | FAQ: 23 | 24 | * Couldn't you just write javascript functions that you call that do the same thing? 25 | 26 | You might but then you introduce the opportunity of syntax and other programming errors, thus not achieving 0 bugs. In practice, this library is so straightforward to use that once you define a complicated action, which only takes a few seconds, you can move it around and it just always works. 27 | 28 | Moreover, it's easier to auto-generate correct readable html (e.g. from Django templates). Many of your pages won't need *any* javascript even if highly dynamic. All the custom logic is in one place rather than spread over the html and the javascript. Basically, writing javascript is harder than what amounts to a DSL in HTML. 29 | 30 | * I need more complicated action-handlers than just these 3, can you please make them? 31 | 32 | The code is open source and on Github on jperla/pebbles. Feel free to add your own enhancements. Be careful because you want to keep your app simple, and, in my experience, these 3 actions comprise the vast majority of user ajax paradigms. With a little thinking you can probably do what you want using either "form-submit" or "replace" with the right response html. 33 | 34 | Technical Documentation: 35 | 36 | 37 | Pebbles accepts spinner url (to an animated gif of a spinner for waits). 38 | Pebbles sets up a live listener on divs with classes of type "actionable". 39 | 40 | Classes of type actionable contain a hidden div which has class "kwargs". 41 | 42 | .actionable .kwargs { display: none; } 43 | 44 | kwargs div contains a number of html elements, each with a name and value. The name is the key name, the value is the value for that key. In this way, in HTML, we specify a dictionary of keyword arguments to the actionable. 45 | 46 | Here are some self-explanatory examples: 47 | 48 | 53 |
      54 | 63 |
      64 | 65 | 69 | 84 | 85 | 86 | 87 | 90 |
      91 |
      92 | show full comment 93 |
      94 | 95 | 96 | 97 | 98 |
      99 |
      100 |
      101 |
      102 | 103 | 104 | 111 |
      112 |
      113 |
      show full comment
      114 |
      hide
      115 |
      116 | 117 | 118 | 119 |
      120 |
      121 |
      122 |
      123 | 124 | 125 | 126 | 127 | It fails loudly if misconfigured. It's hard to write buggy code and not notice in quick testing. It is easy to do everything right and it is easy for you to write a complex ajax website with no extra javascript code. 128 | 129 | 130 | Full arguments are below: 131 | =========================== 132 | Arguments: 133 | type: replace, open-close, submit-form 134 | replace replaces the target with the url 135 | open-close will toggle hide/display the target, which also may dynamically lazily load content from an url 136 | submit-form submits a form via ajax which is a child of the actionable, or may be specified in form argument; the response of the ajax replaces target 137 | 138 | url: url string of remote page contents 139 | 140 | target: CSS3 selector of element on page to update 141 | 142 | target-type: absolute, parent, sibling, closest, or child-of 143 | Absolute just executes the target selector in jQuery. 144 | Parent executes target selector on jQuery.parents(). 145 | Sibling the same on siblings. 146 | Closest looks at children and children of children and so on. 147 | child-of looks at target's children 148 | 149 | closest: selector used in combination with target-type:child-of to get target's children 150 | form: selector used in combination with type:submit-form to find the form 151 | 152 | If you use the open-close type, then the actionable can have two child divs with classes "when-open" and "when-closed". Fill when-open with what the actionable looks like when the target is toggled open (for example, a minus sign), and fill when-closed with what the it looks like when the target is toggled closed (for example, a plus sign). 153 | 154 | -------------------------------------------------------------------------------- /test/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 | runLoggingCallbacks('moduleDone', QUnit, { 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 | runLoggingCallbacks( 'moduleStart', QUnit, { 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 | runLoggingCallbacks( 'testStart', QUnit, { 75 | name: this.testName, 76 | module: this.module 77 | }); 78 | 79 | // allow utility functions to access the current test environment 80 | // TODO why?? 81 | QUnit.current_testEnvironment = this.testEnvironment; 82 | 83 | try { 84 | if ( !config.pollution ) { 85 | saveGlobal(); 86 | } 87 | 88 | this.testEnvironment.setup.call(this.testEnvironment); 89 | } catch(e) { 90 | QUnit.ok( false, "Setup failed on " + this.testName + ": " + e.message ); 91 | } 92 | }, 93 | run: function() { 94 | if ( this.async ) { 95 | QUnit.stop(); 96 | } 97 | 98 | if ( config.notrycatch ) { 99 | this.callback.call(this.testEnvironment); 100 | return; 101 | } 102 | try { 103 | this.callback.call(this.testEnvironment); 104 | } catch(e) { 105 | fail("Test " + this.testName + " died, exception and test follows", e, this.callback); 106 | QUnit.ok( false, "Died on test #" + (this.assertions.length + 1) + ": " + e.message + " - " + QUnit.jsDump.parse(e) ); 107 | // else next test will carry the responsibility 108 | saveGlobal(); 109 | 110 | // Restart the tests if they're blocking 111 | if ( config.blocking ) { 112 | start(); 113 | } 114 | } 115 | }, 116 | teardown: function() { 117 | try { 118 | this.testEnvironment.teardown.call(this.testEnvironment); 119 | checkPollution(); 120 | } catch(e) { 121 | QUnit.ok( false, "Teardown failed on " + this.testName + ": " + e.message ); 122 | } 123 | }, 124 | finish: function() { 125 | if ( this.expected && this.expected != this.assertions.length ) { 126 | QUnit.ok( false, "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run" ); 127 | } 128 | 129 | var good = 0, bad = 0, 130 | tests = id("qunit-tests"); 131 | 132 | config.stats.all += this.assertions.length; 133 | config.moduleStats.all += this.assertions.length; 134 | 135 | if ( tests ) { 136 | var ol = document.createElement("ol"); 137 | 138 | for ( var i = 0; i < this.assertions.length; i++ ) { 139 | var assertion = this.assertions[i]; 140 | 141 | var li = document.createElement("li"); 142 | li.className = assertion.result ? "pass" : "fail"; 143 | li.innerHTML = assertion.message || (assertion.result ? "okay" : "failed"); 144 | ol.appendChild( li ); 145 | 146 | if ( assertion.result ) { 147 | good++; 148 | } else { 149 | bad++; 150 | config.stats.bad++; 151 | config.moduleStats.bad++; 152 | } 153 | } 154 | 155 | // store result when possible 156 | if ( QUnit.config.reorder && defined.sessionStorage ) { 157 | if (bad) { 158 | sessionStorage.setItem("qunit-" + this.module + "-" + this.testName, bad); 159 | } else { 160 | sessionStorage.removeItem("qunit-" + this.module + "-" + this.testName); 161 | } 162 | } 163 | 164 | if (bad == 0) { 165 | ol.style.display = "none"; 166 | } 167 | 168 | var b = document.createElement("strong"); 169 | b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; 170 | 171 | var a = document.createElement("a"); 172 | a.innerHTML = "Rerun"; 173 | a.href = QUnit.url({ filter: getText([b]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); 174 | 175 | addEvent(b, "click", function() { 176 | var next = b.nextSibling.nextSibling, 177 | display = next.style.display; 178 | next.style.display = display === "none" ? "block" : "none"; 179 | }); 180 | 181 | addEvent(b, "dblclick", function(e) { 182 | var target = e && e.target ? e.target : window.event.srcElement; 183 | if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { 184 | target = target.parentNode; 185 | } 186 | if ( window.location && target.nodeName.toLowerCase() === "strong" ) { 187 | window.location = QUnit.url({ filter: getText([target]).replace(/\([^)]+\)$/, "").replace(/(^\s*|\s*$)/g, "") }); 188 | } 189 | }); 190 | 191 | var li = id(this.id); 192 | li.className = bad ? "fail" : "pass"; 193 | li.removeChild( li.firstChild ); 194 | li.appendChild( b ); 195 | li.appendChild( a ); 196 | li.appendChild( ol ); 197 | 198 | } else { 199 | for ( var i = 0; i < this.assertions.length; i++ ) { 200 | if ( !this.assertions[i].result ) { 201 | bad++; 202 | config.stats.bad++; 203 | config.moduleStats.bad++; 204 | } 205 | } 206 | } 207 | 208 | try { 209 | QUnit.reset(); 210 | } catch(e) { 211 | fail("reset() failed, following Test " + this.testName + ", exception and reset fn follows", e, QUnit.reset); 212 | } 213 | 214 | runLoggingCallbacks( 'testDone', QUnit, { 215 | name: this.testName, 216 | module: this.module, 217 | failed: bad, 218 | passed: this.assertions.length - bad, 219 | total: this.assertions.length 220 | } ); 221 | }, 222 | 223 | queue: function() { 224 | var test = this; 225 | synchronize(function() { 226 | test.init(); 227 | }); 228 | function run() { 229 | // each of these can by async 230 | synchronize(function() { 231 | test.setup(); 232 | }); 233 | synchronize(function() { 234 | test.run(); 235 | }); 236 | synchronize(function() { 237 | test.teardown(); 238 | }); 239 | synchronize(function() { 240 | test.finish(); 241 | }); 242 | } 243 | // defer when previous test run passed, if storage is available 244 | var bad = QUnit.config.reorder && defined.sessionStorage && +sessionStorage.getItem("qunit-" + this.module + "-" + this.testName); 245 | if (bad) { 246 | run(); 247 | } else { 248 | synchronize(run); 249 | }; 250 | } 251 | 252 | }; 253 | 254 | var QUnit = { 255 | 256 | // call on start of module test to prepend name to all tests 257 | module: function(name, testEnvironment) { 258 | config.currentModule = name; 259 | config.currentModuleTestEnviroment = testEnvironment; 260 | }, 261 | 262 | asyncTest: function(testName, expected, callback) { 263 | if ( arguments.length === 2 ) { 264 | callback = expected; 265 | expected = 0; 266 | } 267 | 268 | QUnit.test(testName, expected, callback, true); 269 | }, 270 | 271 | test: function(testName, expected, callback, async) { 272 | var name = '' + testName + '', testEnvironmentArg; 273 | 274 | if ( arguments.length === 2 ) { 275 | callback = expected; 276 | expected = null; 277 | } 278 | // is 2nd argument a testEnvironment? 279 | if ( expected && typeof expected === 'object') { 280 | testEnvironmentArg = expected; 281 | expected = null; 282 | } 283 | 284 | if ( config.currentModule ) { 285 | name = '' + config.currentModule + ": " + name; 286 | } 287 | 288 | if ( !validTest(config.currentModule + ": " + testName) ) { 289 | return; 290 | } 291 | 292 | var test = new Test(name, testName, expected, testEnvironmentArg, async, callback); 293 | test.module = config.currentModule; 294 | test.moduleTestEnvironment = config.currentModuleTestEnviroment; 295 | test.queue(); 296 | }, 297 | 298 | /** 299 | * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. 300 | */ 301 | expect: function(asserts) { 302 | config.current.expected = asserts; 303 | }, 304 | 305 | /** 306 | * Asserts true. 307 | * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); 308 | */ 309 | ok: function(a, msg) { 310 | a = !!a; 311 | var details = { 312 | result: a, 313 | message: msg 314 | }; 315 | msg = escapeInnerText(msg); 316 | runLoggingCallbacks( 'log', QUnit, details ); 317 | config.current.assertions.push({ 318 | result: a, 319 | message: msg 320 | }); 321 | }, 322 | 323 | /** 324 | * Checks that the first two arguments are equal, with an optional message. 325 | * Prints out both actual and expected values. 326 | * 327 | * Prefered to ok( actual == expected, message ) 328 | * 329 | * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); 330 | * 331 | * @param Object actual 332 | * @param Object expected 333 | * @param String message (optional) 334 | */ 335 | equal: function(actual, expected, message) { 336 | QUnit.push(expected == actual, actual, expected, message); 337 | }, 338 | 339 | notEqual: function(actual, expected, message) { 340 | QUnit.push(expected != actual, actual, expected, message); 341 | }, 342 | 343 | deepEqual: function(actual, expected, message) { 344 | QUnit.push(QUnit.equiv(actual, expected), actual, expected, message); 345 | }, 346 | 347 | notDeepEqual: function(actual, expected, message) { 348 | QUnit.push(!QUnit.equiv(actual, expected), actual, expected, message); 349 | }, 350 | 351 | strictEqual: function(actual, expected, message) { 352 | QUnit.push(expected === actual, actual, expected, message); 353 | }, 354 | 355 | notStrictEqual: function(actual, expected, message) { 356 | QUnit.push(expected !== actual, actual, expected, message); 357 | }, 358 | 359 | raises: function(block, expected, message) { 360 | var actual, ok = false; 361 | 362 | if (typeof expected === 'string') { 363 | message = expected; 364 | expected = null; 365 | } 366 | 367 | try { 368 | block(); 369 | } catch (e) { 370 | actual = e; 371 | } 372 | 373 | if (actual) { 374 | // we don't want to validate thrown error 375 | if (!expected) { 376 | ok = true; 377 | // expected is a regexp 378 | } else if (QUnit.objectType(expected) === "regexp") { 379 | ok = expected.test(actual); 380 | // expected is a constructor 381 | } else if (actual instanceof expected) { 382 | ok = true; 383 | // expected is a validation function which returns true is validation passed 384 | } else if (expected.call({}, actual) === true) { 385 | ok = true; 386 | } 387 | } 388 | 389 | QUnit.ok(ok, message); 390 | }, 391 | 392 | start: function(count) { 393 | config.semaphore -= count || 1; 394 | if (config.semaphore > 0) { 395 | // don't start until equal number of stop-calls 396 | return; 397 | } 398 | if (config.semaphore < 0) { 399 | // ignore if start is called more often then stop 400 | config.semaphore = 0; 401 | } 402 | // A slight delay, to avoid any current callbacks 403 | if ( defined.setTimeout ) { 404 | window.setTimeout(function() { 405 | if (config.semaphore > 0) { 406 | return; 407 | } 408 | if ( config.timeout ) { 409 | clearTimeout(config.timeout); 410 | } 411 | 412 | config.blocking = false; 413 | process(); 414 | }, 13); 415 | } else { 416 | config.blocking = false; 417 | process(); 418 | } 419 | }, 420 | 421 | stop: function(count) { 422 | config.semaphore += count || 1; 423 | config.blocking = true; 424 | 425 | if ( config.testTimeout && defined.setTimeout ) { 426 | clearTimeout(config.timeout); 427 | config.timeout = window.setTimeout(function() { 428 | QUnit.ok( false, "Test timed out" ); 429 | config.semaphore = 1; 430 | QUnit.start(); 431 | }, config.testTimeout); 432 | } 433 | } 434 | }; 435 | 436 | //We want access to the constructor's prototype 437 | (function() { 438 | function F(){}; 439 | F.prototype = QUnit; 440 | QUnit = new F(); 441 | //Make F QUnit's constructor so that we can add to the prototype later 442 | QUnit.constructor = F; 443 | })(); 444 | 445 | // Backwards compatibility, deprecated 446 | QUnit.equals = QUnit.equal; 447 | QUnit.same = QUnit.deepEqual; 448 | 449 | // Maintain internal state 450 | var config = { 451 | // The queue of tests to run 452 | queue: [], 453 | 454 | // block until document ready 455 | blocking: true, 456 | 457 | // when enabled, show only failing tests 458 | // gets persisted through sessionStorage and can be changed in UI via checkbox 459 | hidepassed: false, 460 | 461 | // by default, run previously failed tests first 462 | // very useful in combination with "Hide passed tests" checked 463 | reorder: true, 464 | 465 | // by default, modify document.title when suite is done 466 | altertitle: true, 467 | 468 | urlConfig: ['noglobals', 'notrycatch'], 469 | 470 | //logging callback queues 471 | begin: [], 472 | done: [], 473 | log: [], 474 | testStart: [], 475 | testDone: [], 476 | moduleStart: [], 477 | moduleDone: [] 478 | }; 479 | 480 | // Load paramaters 481 | (function() { 482 | var location = window.location || { search: "", protocol: "file:" }, 483 | params = location.search.slice( 1 ).split( "&" ), 484 | length = params.length, 485 | urlParams = {}, 486 | current; 487 | 488 | if ( params[ 0 ] ) { 489 | for ( var i = 0; i < length; i++ ) { 490 | current = params[ i ].split( "=" ); 491 | current[ 0 ] = decodeURIComponent( current[ 0 ] ); 492 | // allow just a key to turn on a flag, e.g., test.html?noglobals 493 | current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; 494 | urlParams[ current[ 0 ] ] = current[ 1 ]; 495 | } 496 | } 497 | 498 | QUnit.urlParams = urlParams; 499 | config.filter = urlParams.filter; 500 | 501 | // Figure out if we're running the tests from a server or not 502 | QUnit.isLocal = !!(location.protocol === 'file:'); 503 | })(); 504 | 505 | // Expose the API as global variables, unless an 'exports' 506 | // object exists, in that case we assume we're in CommonJS 507 | if ( typeof exports === "undefined" || typeof require === "undefined" ) { 508 | extend(window, QUnit); 509 | window.QUnit = QUnit; 510 | } else { 511 | extend(exports, QUnit); 512 | exports.QUnit = QUnit; 513 | } 514 | 515 | // define these after exposing globals to keep them in these QUnit namespace only 516 | extend(QUnit, { 517 | config: config, 518 | 519 | // Initialize the configuration options 520 | init: function() { 521 | extend(config, { 522 | stats: { all: 0, bad: 0 }, 523 | moduleStats: { all: 0, bad: 0 }, 524 | started: +new Date, 525 | updateRate: 1000, 526 | blocking: false, 527 | autostart: true, 528 | autorun: false, 529 | filter: "", 530 | queue: [], 531 | semaphore: 0 532 | }); 533 | 534 | var tests = id( "qunit-tests" ), 535 | banner = id( "qunit-banner" ), 536 | result = id( "qunit-testresult" ); 537 | 538 | if ( tests ) { 539 | tests.innerHTML = ""; 540 | } 541 | 542 | if ( banner ) { 543 | banner.className = ""; 544 | } 545 | 546 | if ( result ) { 547 | result.parentNode.removeChild( result ); 548 | } 549 | 550 | if ( tests ) { 551 | result = document.createElement( "p" ); 552 | result.id = "qunit-testresult"; 553 | result.className = "result"; 554 | tests.parentNode.insertBefore( result, tests ); 555 | result.innerHTML = 'Running...
       '; 556 | } 557 | }, 558 | 559 | /** 560 | * Resets the test setup. Useful for tests that modify the DOM. 561 | * 562 | * If jQuery is available, uses jQuery's html(), otherwise just innerHTML. 563 | */ 564 | reset: function() { 565 | if ( window.jQuery ) { 566 | jQuery( "#qunit-fixture" ).html( config.fixture ); 567 | } else { 568 | var main = id( 'qunit-fixture' ); 569 | if ( main ) { 570 | main.innerHTML = config.fixture; 571 | } 572 | } 573 | }, 574 | 575 | /** 576 | * Trigger an event on an element. 577 | * 578 | * @example triggerEvent( document.body, "click" ); 579 | * 580 | * @param DOMElement elem 581 | * @param String type 582 | */ 583 | triggerEvent: function( elem, type, event ) { 584 | if ( document.createEvent ) { 585 | event = document.createEvent("MouseEvents"); 586 | event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, 587 | 0, 0, 0, 0, 0, false, false, false, false, 0, null); 588 | elem.dispatchEvent( event ); 589 | 590 | } else if ( elem.fireEvent ) { 591 | elem.fireEvent("on"+type); 592 | } 593 | }, 594 | 595 | // Safe object type checking 596 | is: function( type, obj ) { 597 | return QUnit.objectType( obj ) == type; 598 | }, 599 | 600 | objectType: function( obj ) { 601 | if (typeof obj === "undefined") { 602 | return "undefined"; 603 | 604 | // consider: typeof null === object 605 | } 606 | if (obj === null) { 607 | return "null"; 608 | } 609 | 610 | var type = Object.prototype.toString.call( obj ) 611 | .match(/^\[object\s(.*)\]$/)[1] || ''; 612 | 613 | switch (type) { 614 | case 'Number': 615 | if (isNaN(obj)) { 616 | return "nan"; 617 | } else { 618 | return "number"; 619 | } 620 | case 'String': 621 | case 'Boolean': 622 | case 'Array': 623 | case 'Date': 624 | case 'RegExp': 625 | case 'Function': 626 | return type.toLowerCase(); 627 | } 628 | if (typeof obj === "object") { 629 | return "object"; 630 | } 631 | return undefined; 632 | }, 633 | 634 | push: function(result, actual, expected, message) { 635 | var details = { 636 | result: result, 637 | message: message, 638 | actual: actual, 639 | expected: expected 640 | }; 641 | 642 | message = escapeInnerText(message) || (result ? "okay" : "failed"); 643 | message = '' + message + ""; 644 | expected = escapeInnerText(QUnit.jsDump.parse(expected)); 645 | actual = escapeInnerText(QUnit.jsDump.parse(actual)); 646 | var output = message + ''; 647 | if (actual != expected) { 648 | output += ''; 649 | output += ''; 650 | } 651 | if (!result) { 652 | var source = sourceFromStacktrace(); 653 | if (source) { 654 | details.source = source; 655 | output += ''; 656 | } 657 | } 658 | output += "
      Expected:
      ' + expected + '
      Result:
      ' + actual + '
      Diff:
      ' + QUnit.diff(expected, actual) +'
      Source:
      ' + escapeInnerText(source) + '
      "; 659 | 660 | runLoggingCallbacks( 'log', QUnit, details ); 661 | 662 | config.current.assertions.push({ 663 | result: !!result, 664 | message: output 665 | }); 666 | }, 667 | 668 | url: function( params ) { 669 | params = extend( extend( {}, QUnit.urlParams ), params ); 670 | var querystring = "?", 671 | key; 672 | for ( key in params ) { 673 | querystring += encodeURIComponent( key ) + "=" + 674 | encodeURIComponent( params[ key ] ) + "&"; 675 | } 676 | return window.location.pathname + querystring.slice( 0, -1 ); 677 | }, 678 | 679 | extend: extend, 680 | id: id, 681 | addEvent: addEvent 682 | }); 683 | 684 | //QUnit.constructor is set to the empty F() above so that we can add to it's prototype later 685 | //Doing this allows us to tell if the following methods have been overwritten on the actual 686 | //QUnit object, which is a deprecated way of using the callbacks. 687 | extend(QUnit.constructor.prototype, { 688 | // Logging callbacks; all receive a single argument with the listed properties 689 | // run test/logs.html for any related changes 690 | begin: registerLoggingCallback('begin'), 691 | // done: { failed, passed, total, runtime } 692 | done: registerLoggingCallback('done'), 693 | // log: { result, actual, expected, message } 694 | log: registerLoggingCallback('log'), 695 | // testStart: { name } 696 | testStart: registerLoggingCallback('testStart'), 697 | // testDone: { name, failed, passed, total } 698 | testDone: registerLoggingCallback('testDone'), 699 | // moduleStart: { name } 700 | moduleStart: registerLoggingCallback('moduleStart'), 701 | // moduleDone: { name, failed, passed, total } 702 | moduleDone: registerLoggingCallback('moduleDone') 703 | }); 704 | 705 | if ( typeof document === "undefined" || document.readyState === "complete" ) { 706 | config.autorun = true; 707 | } 708 | 709 | QUnit.load = function() { 710 | runLoggingCallbacks( 'begin', QUnit, {} ); 711 | 712 | // Initialize the config, saving the execution queue 713 | var oldconfig = extend({}, config); 714 | QUnit.init(); 715 | extend(config, oldconfig); 716 | 717 | config.blocking = false; 718 | 719 | var urlConfigHtml = '', len = config.urlConfig.length; 720 | for ( var i = 0, val; i < len, val = config.urlConfig[i]; i++ ) { 721 | config[val] = QUnit.urlParams[val]; 722 | urlConfigHtml += ''; 723 | } 724 | 725 | var userAgent = id("qunit-userAgent"); 726 | if ( userAgent ) { 727 | userAgent.innerHTML = navigator.userAgent; 728 | } 729 | var banner = id("qunit-header"); 730 | if ( banner ) { 731 | banner.innerHTML = ' ' + banner.innerHTML + ' ' + urlConfigHtml; 732 | addEvent( banner, "change", function( event ) { 733 | var params = {}; 734 | params[ event.target.name ] = event.target.checked ? true : undefined; 735 | window.location = QUnit.url( params ); 736 | }); 737 | } 738 | 739 | var toolbar = id("qunit-testrunner-toolbar"); 740 | if ( toolbar ) { 741 | var filter = document.createElement("input"); 742 | filter.type = "checkbox"; 743 | filter.id = "qunit-filter-pass"; 744 | addEvent( filter, "click", function() { 745 | var ol = document.getElementById("qunit-tests"); 746 | if ( filter.checked ) { 747 | ol.className = ol.className + " hidepass"; 748 | } else { 749 | var tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; 750 | ol.className = tmp.replace(/ hidepass /, " "); 751 | } 752 | if ( defined.sessionStorage ) { 753 | if (filter.checked) { 754 | sessionStorage.setItem("qunit-filter-passed-tests", "true"); 755 | } else { 756 | sessionStorage.removeItem("qunit-filter-passed-tests"); 757 | } 758 | } 759 | }); 760 | if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem("qunit-filter-passed-tests") ) { 761 | filter.checked = true; 762 | var ol = document.getElementById("qunit-tests"); 763 | ol.className = ol.className + " hidepass"; 764 | } 765 | toolbar.appendChild( filter ); 766 | 767 | var label = document.createElement("label"); 768 | label.setAttribute("for", "qunit-filter-pass"); 769 | label.innerHTML = "Hide passed tests"; 770 | toolbar.appendChild( label ); 771 | } 772 | 773 | var main = id('qunit-fixture'); 774 | if ( main ) { 775 | config.fixture = main.innerHTML; 776 | } 777 | 778 | if (config.autostart) { 779 | QUnit.start(); 780 | } 781 | }; 782 | 783 | addEvent(window, "load", QUnit.load); 784 | 785 | function done() { 786 | config.autorun = true; 787 | 788 | // Log the last module results 789 | if ( config.currentModule ) { 790 | runLoggingCallbacks( 'moduleDone', QUnit, { 791 | name: config.currentModule, 792 | failed: config.moduleStats.bad, 793 | passed: config.moduleStats.all - config.moduleStats.bad, 794 | total: config.moduleStats.all 795 | } ); 796 | } 797 | 798 | var banner = id("qunit-banner"), 799 | tests = id("qunit-tests"), 800 | runtime = +new Date - config.started, 801 | passed = config.stats.all - config.stats.bad, 802 | html = [ 803 | 'Tests completed in ', 804 | runtime, 805 | ' milliseconds.
      ', 806 | '', 807 | passed, 808 | ' tests of ', 809 | config.stats.all, 810 | ' passed, ', 811 | config.stats.bad, 812 | ' failed.' 813 | ].join(''); 814 | 815 | if ( banner ) { 816 | banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); 817 | } 818 | 819 | if ( tests ) { 820 | id( "qunit-testresult" ).innerHTML = html; 821 | } 822 | 823 | if ( config.altertitle && typeof document !== "undefined" && document.title ) { 824 | // show ✖ for good, ✔ for bad suite result in title 825 | // use escape sequences in case file gets loaded with non-utf-8-charset 826 | document.title = [ 827 | (config.stats.bad ? "\u2716" : "\u2714"), 828 | document.title.replace(/^[\u2714\u2716] /i, "") 829 | ].join(" "); 830 | } 831 | 832 | runLoggingCallbacks( 'done', QUnit, { 833 | failed: config.stats.bad, 834 | passed: passed, 835 | total: config.stats.all, 836 | runtime: runtime 837 | } ); 838 | } 839 | 840 | function validTest( name ) { 841 | var filter = config.filter, 842 | run = false; 843 | 844 | if ( !filter ) { 845 | return true; 846 | } 847 | 848 | var not = filter.charAt( 0 ) === "!"; 849 | if ( not ) { 850 | filter = filter.slice( 1 ); 851 | } 852 | 853 | if ( name.indexOf( filter ) !== -1 ) { 854 | return !not; 855 | } 856 | 857 | if ( not ) { 858 | run = true; 859 | } 860 | 861 | return run; 862 | } 863 | 864 | // so far supports only Firefox, Chrome and Opera (buggy) 865 | // could be extended in the future to use something like https://github.com/csnover/TraceKit 866 | function sourceFromStacktrace() { 867 | try { 868 | throw new Error(); 869 | } catch ( e ) { 870 | if (e.stacktrace) { 871 | // Opera 872 | return e.stacktrace.split("\n")[6]; 873 | } else if (e.stack) { 874 | // Firefox, Chrome 875 | return e.stack.split("\n")[4]; 876 | } else if (e.sourceURL) { 877 | // Safari, PhantomJS 878 | // TODO sourceURL points at the 'throw new Error' line above, useless 879 | //return e.sourceURL + ":" + e.line; 880 | } 881 | } 882 | } 883 | 884 | function escapeInnerText(s) { 885 | if (!s) { 886 | return ""; 887 | } 888 | s = s + ""; 889 | return s.replace(/[\&<>]/g, function(s) { 890 | switch(s) { 891 | case "&": return "&"; 892 | case "<": return "<"; 893 | case ">": return ">"; 894 | default: return s; 895 | } 896 | }); 897 | } 898 | 899 | function synchronize( callback ) { 900 | config.queue.push( callback ); 901 | 902 | if ( config.autorun && !config.blocking ) { 903 | process(); 904 | } 905 | } 906 | 907 | function process() { 908 | var start = (new Date()).getTime(); 909 | 910 | while ( config.queue.length && !config.blocking ) { 911 | if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) { 912 | config.queue.shift()(); 913 | } else { 914 | window.setTimeout( process, 13 ); 915 | break; 916 | } 917 | } 918 | if (!config.blocking && !config.queue.length) { 919 | done(); 920 | } 921 | } 922 | 923 | function saveGlobal() { 924 | config.pollution = []; 925 | 926 | if ( config.noglobals ) { 927 | for ( var key in window ) { 928 | config.pollution.push( key ); 929 | } 930 | } 931 | } 932 | 933 | function checkPollution( name ) { 934 | var old = config.pollution; 935 | saveGlobal(); 936 | 937 | var newGlobals = diff( config.pollution, old ); 938 | if ( newGlobals.length > 0 ) { 939 | ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); 940 | } 941 | 942 | var deletedGlobals = diff( old, config.pollution ); 943 | if ( deletedGlobals.length > 0 ) { 944 | ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); 945 | } 946 | } 947 | 948 | // returns a new Array with the elements that are in a but not in b 949 | function diff( a, b ) { 950 | var result = a.slice(); 951 | for ( var i = 0; i < result.length; i++ ) { 952 | for ( var j = 0; j < b.length; j++ ) { 953 | if ( result[i] === b[j] ) { 954 | result.splice(i, 1); 955 | i--; 956 | break; 957 | } 958 | } 959 | } 960 | return result; 961 | } 962 | 963 | function fail(message, exception, callback) { 964 | if ( typeof console !== "undefined" && console.error && console.warn ) { 965 | console.error(message); 966 | console.error(exception); 967 | console.warn(callback.toString()); 968 | 969 | } else if ( window.opera && opera.postError ) { 970 | opera.postError(message, exception, callback.toString); 971 | } 972 | } 973 | 974 | function extend(a, b) { 975 | for ( var prop in b ) { 976 | if ( b[prop] === undefined ) { 977 | delete a[prop]; 978 | } else { 979 | a[prop] = b[prop]; 980 | } 981 | } 982 | 983 | return a; 984 | } 985 | 986 | function addEvent(elem, type, fn) { 987 | if ( elem.addEventListener ) { 988 | elem.addEventListener( type, fn, false ); 989 | } else if ( elem.attachEvent ) { 990 | elem.attachEvent( "on" + type, fn ); 991 | } else { 992 | fn(); 993 | } 994 | } 995 | 996 | function id(name) { 997 | return !!(typeof document !== "undefined" && document && document.getElementById) && 998 | document.getElementById( name ); 999 | } 1000 | 1001 | function registerLoggingCallback(key){ 1002 | return function(callback){ 1003 | config[key].push( callback ); 1004 | }; 1005 | } 1006 | 1007 | // Supports deprecated method of completely overwriting logging callbacks 1008 | function runLoggingCallbacks(key, scope, args) { 1009 | //debugger; 1010 | var callbacks; 1011 | if ( QUnit.hasOwnProperty(key) ) { 1012 | QUnit[key].call(scope, args); 1013 | } else { 1014 | callbacks = config[key]; 1015 | for( var i = 0; i < callbacks.length; i++ ) { 1016 | callbacks[i].call( scope, args ); 1017 | } 1018 | } 1019 | } 1020 | 1021 | // Test for equality any JavaScript type. 1022 | // Author: Philippe Rathé 1023 | QUnit.equiv = function () { 1024 | 1025 | var innerEquiv; // the real equiv function 1026 | var callers = []; // stack to decide between skip/abort functions 1027 | var parents = []; // stack to avoiding loops from circular referencing 1028 | 1029 | // Call the o related callback with the given arguments. 1030 | function bindCallbacks(o, callbacks, args) { 1031 | var prop = QUnit.objectType(o); 1032 | if (prop) { 1033 | if (QUnit.objectType(callbacks[prop]) === "function") { 1034 | return callbacks[prop].apply(callbacks, args); 1035 | } else { 1036 | return callbacks[prop]; // or undefined 1037 | } 1038 | } 1039 | } 1040 | 1041 | var callbacks = function () { 1042 | 1043 | // for string, boolean, number and null 1044 | function useStrictEquality(b, a) { 1045 | if (b instanceof a.constructor || a instanceof b.constructor) { 1046 | // to catch short annotaion VS 'new' annotation of a 1047 | // declaration 1048 | // e.g. var i = 1; 1049 | // var j = new Number(1); 1050 | return a == b; 1051 | } else { 1052 | return a === b; 1053 | } 1054 | } 1055 | 1056 | return { 1057 | "string" : useStrictEquality, 1058 | "boolean" : useStrictEquality, 1059 | "number" : useStrictEquality, 1060 | "null" : useStrictEquality, 1061 | "undefined" : useStrictEquality, 1062 | 1063 | "nan" : function(b) { 1064 | return isNaN(b); 1065 | }, 1066 | 1067 | "date" : function(b, a) { 1068 | return QUnit.objectType(b) === "date" 1069 | && a.valueOf() === b.valueOf(); 1070 | }, 1071 | 1072 | "regexp" : function(b, a) { 1073 | return QUnit.objectType(b) === "regexp" 1074 | && a.source === b.source && // the regex itself 1075 | a.global === b.global && // and its modifers 1076 | // (gmi) ... 1077 | a.ignoreCase === b.ignoreCase 1078 | && a.multiline === b.multiline; 1079 | }, 1080 | 1081 | // - skip when the property is a method of an instance (OOP) 1082 | // - abort otherwise, 1083 | // initial === would have catch identical references anyway 1084 | "function" : function() { 1085 | var caller = callers[callers.length - 1]; 1086 | return caller !== Object && typeof caller !== "undefined"; 1087 | }, 1088 | 1089 | "array" : function(b, a) { 1090 | var i, j, loop; 1091 | var len; 1092 | 1093 | // b could be an object literal here 1094 | if (!(QUnit.objectType(b) === "array")) { 1095 | return false; 1096 | } 1097 | 1098 | len = a.length; 1099 | if (len !== b.length) { // safe and faster 1100 | return false; 1101 | } 1102 | 1103 | // track reference to avoid circular references 1104 | parents.push(a); 1105 | for (i = 0; i < len; i++) { 1106 | loop = false; 1107 | for (j = 0; j < parents.length; j++) { 1108 | if (parents[j] === a[i]) { 1109 | loop = true;// dont rewalk array 1110 | } 1111 | } 1112 | if (!loop && !innerEquiv(a[i], b[i])) { 1113 | parents.pop(); 1114 | return false; 1115 | } 1116 | } 1117 | parents.pop(); 1118 | return true; 1119 | }, 1120 | 1121 | "object" : function(b, a) { 1122 | var i, j, loop; 1123 | var eq = true; // unless we can proove it 1124 | var aProperties = [], bProperties = []; // collection of 1125 | // strings 1126 | 1127 | // comparing constructors is more strict than using 1128 | // instanceof 1129 | if (a.constructor !== b.constructor) { 1130 | return false; 1131 | } 1132 | 1133 | // stack constructor before traversing properties 1134 | callers.push(a.constructor); 1135 | // track reference to avoid circular references 1136 | parents.push(a); 1137 | 1138 | for (i in a) { // be strict: don't ensures hasOwnProperty 1139 | // and go deep 1140 | loop = false; 1141 | for (j = 0; j < parents.length; j++) { 1142 | if (parents[j] === a[i]) 1143 | loop = true; // don't go down the same path 1144 | // twice 1145 | } 1146 | aProperties.push(i); // collect a's properties 1147 | 1148 | if (!loop && !innerEquiv(a[i], b[i])) { 1149 | eq = false; 1150 | break; 1151 | } 1152 | } 1153 | 1154 | callers.pop(); // unstack, we are done 1155 | parents.pop(); 1156 | 1157 | for (i in b) { 1158 | bProperties.push(i); // collect b's properties 1159 | } 1160 | 1161 | // Ensures identical properties name 1162 | return eq 1163 | && innerEquiv(aProperties.sort(), bProperties 1164 | .sort()); 1165 | } 1166 | }; 1167 | }(); 1168 | 1169 | innerEquiv = function() { // can take multiple arguments 1170 | var args = Array.prototype.slice.apply(arguments); 1171 | if (args.length < 2) { 1172 | return true; // end transition 1173 | } 1174 | 1175 | return (function(a, b) { 1176 | if (a === b) { 1177 | return true; // catch the most you can 1178 | } else if (a === null || b === null || typeof a === "undefined" 1179 | || typeof b === "undefined" 1180 | || QUnit.objectType(a) !== QUnit.objectType(b)) { 1181 | return false; // don't lose time with error prone cases 1182 | } else { 1183 | return bindCallbacks(a, callbacks, [ b, a ]); 1184 | } 1185 | 1186 | // apply transition with (1..n) arguments 1187 | })(args[0], args[1]) 1188 | && arguments.callee.apply(this, args.splice(1, 1189 | args.length - 1)); 1190 | }; 1191 | 1192 | return innerEquiv; 1193 | 1194 | }(); 1195 | 1196 | /** 1197 | * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | 1198 | * http://flesler.blogspot.com Licensed under BSD 1199 | * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 1200 | * 1201 | * @projectDescription Advanced and extensible data dumping for Javascript. 1202 | * @version 1.0.0 1203 | * @author Ariel Flesler 1204 | * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} 1205 | */ 1206 | QUnit.jsDump = (function() { 1207 | function quote( str ) { 1208 | return '"' + str.toString().replace(/"/g, '\\"') + '"'; 1209 | }; 1210 | function literal( o ) { 1211 | return o + ''; 1212 | }; 1213 | function join( pre, arr, post ) { 1214 | var s = jsDump.separator(), 1215 | base = jsDump.indent(), 1216 | inner = jsDump.indent(1); 1217 | if ( arr.join ) 1218 | arr = arr.join( ',' + s + inner ); 1219 | if ( !arr ) 1220 | return pre + post; 1221 | return [ pre, inner + arr, base + post ].join(s); 1222 | }; 1223 | function array( arr, stack ) { 1224 | var i = arr.length, ret = Array(i); 1225 | this.up(); 1226 | while ( i-- ) 1227 | ret[i] = this.parse( arr[i] , undefined , stack); 1228 | this.down(); 1229 | return join( '[', ret, ']' ); 1230 | }; 1231 | 1232 | var reName = /^function (\w+)/; 1233 | 1234 | var jsDump = { 1235 | parse:function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance 1236 | stack = stack || [ ]; 1237 | var parser = this.parsers[ type || this.typeOf(obj) ]; 1238 | type = typeof parser; 1239 | var inStack = inArray(obj, stack); 1240 | if (inStack != -1) { 1241 | return 'recursion('+(inStack - stack.length)+')'; 1242 | } 1243 | //else 1244 | if (type == 'function') { 1245 | stack.push(obj); 1246 | var res = parser.call( this, obj, stack ); 1247 | stack.pop(); 1248 | return res; 1249 | } 1250 | // else 1251 | return (type == 'string') ? parser : this.parsers.error; 1252 | }, 1253 | typeOf:function( obj ) { 1254 | var type; 1255 | if ( obj === null ) { 1256 | type = "null"; 1257 | } else if (typeof obj === "undefined") { 1258 | type = "undefined"; 1259 | } else if (QUnit.is("RegExp", obj)) { 1260 | type = "regexp"; 1261 | } else if (QUnit.is("Date", obj)) { 1262 | type = "date"; 1263 | } else if (QUnit.is("Function", obj)) { 1264 | type = "function"; 1265 | } else if (typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined") { 1266 | type = "window"; 1267 | } else if (obj.nodeType === 9) { 1268 | type = "document"; 1269 | } else if (obj.nodeType) { 1270 | type = "node"; 1271 | } else if (typeof obj === "object" && typeof obj.length === "number" && obj.length >= 0) { 1272 | type = "array"; 1273 | } else { 1274 | type = typeof obj; 1275 | } 1276 | return type; 1277 | }, 1278 | separator:function() { 1279 | return this.multiline ? this.HTML ? '
      ' : '\n' : this.HTML ? ' ' : ' '; 1280 | }, 1281 | indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing 1282 | if ( !this.multiline ) 1283 | return ''; 1284 | var chr = this.indentChar; 1285 | if ( this.HTML ) 1286 | chr = chr.replace(/\t/g,' ').replace(/ /g,' '); 1287 | return Array( this._depth_ + (extra||0) ).join(chr); 1288 | }, 1289 | up:function( a ) { 1290 | this._depth_ += a || 1; 1291 | }, 1292 | down:function( a ) { 1293 | this._depth_ -= a || 1; 1294 | }, 1295 | setParser:function( name, parser ) { 1296 | this.parsers[name] = parser; 1297 | }, 1298 | // The next 3 are exposed so you can use them 1299 | quote:quote, 1300 | literal:literal, 1301 | join:join, 1302 | // 1303 | _depth_: 1, 1304 | // This is the list of parsers, to modify them, use jsDump.setParser 1305 | parsers:{ 1306 | window: '[Window]', 1307 | document: '[Document]', 1308 | error:'[ERROR]', //when no parser is found, shouldn't happen 1309 | unknown: '[Unknown]', 1310 | 'null':'null', 1311 | 'undefined':'undefined', 1312 | 'function':function( fn ) { 1313 | var ret = 'function', 1314 | name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE 1315 | if ( name ) 1316 | ret += ' ' + name; 1317 | ret += '('; 1318 | 1319 | ret = [ ret, QUnit.jsDump.parse( fn, 'functionArgs' ), '){'].join(''); 1320 | return join( ret, QUnit.jsDump.parse(fn,'functionCode'), '}' ); 1321 | }, 1322 | array: array, 1323 | nodelist: array, 1324 | arguments: array, 1325 | object:function( map, stack ) { 1326 | var ret = [ ]; 1327 | QUnit.jsDump.up(); 1328 | for ( var key in map ) { 1329 | var val = map[key]; 1330 | ret.push( QUnit.jsDump.parse(key,'key') + ': ' + QUnit.jsDump.parse(val, undefined, stack)); 1331 | } 1332 | QUnit.jsDump.down(); 1333 | return join( '{', ret, '}' ); 1334 | }, 1335 | node:function( node ) { 1336 | var open = QUnit.jsDump.HTML ? '<' : '<', 1337 | close = QUnit.jsDump.HTML ? '>' : '>'; 1338 | 1339 | var tag = node.nodeName.toLowerCase(), 1340 | ret = open + tag; 1341 | 1342 | for ( var a in QUnit.jsDump.DOMAttrs ) { 1343 | var val = node[QUnit.jsDump.DOMAttrs[a]]; 1344 | if ( val ) 1345 | ret += ' ' + a + '=' + QUnit.jsDump.parse( val, 'attribute' ); 1346 | } 1347 | return ret + close + open + '/' + tag + close; 1348 | }, 1349 | functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function 1350 | var l = fn.length; 1351 | if ( !l ) return ''; 1352 | 1353 | var args = Array(l); 1354 | while ( l-- ) 1355 | args[l] = String.fromCharCode(97+l);//97 is 'a' 1356 | return ' ' + args.join(', ') + ' '; 1357 | }, 1358 | key:quote, //object calls it internally, the key part of an item in a map 1359 | functionCode:'[code]', //function calls it internally, it's the content of the function 1360 | attribute:quote, //node calls it internally, it's an html attribute value 1361 | string:quote, 1362 | date:quote, 1363 | regexp:literal, //regex 1364 | number:literal, 1365 | 'boolean':literal 1366 | }, 1367 | DOMAttrs:{//attributes to dump from nodes, name=>realName 1368 | id:'id', 1369 | name:'name', 1370 | 'class':'className' 1371 | }, 1372 | HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) 1373 | indentChar:' ',//indentation unit 1374 | multiline:true //if true, items in a collection, are separated by a \n, else just a space. 1375 | }; 1376 | 1377 | return jsDump; 1378 | })(); 1379 | 1380 | // from Sizzle.js 1381 | function getText( elems ) { 1382 | var ret = "", elem; 1383 | 1384 | for ( var i = 0; elems[i]; i++ ) { 1385 | elem = elems[i]; 1386 | 1387 | // Get the text from text nodes and CDATA nodes 1388 | if ( elem.nodeType === 3 || elem.nodeType === 4 ) { 1389 | ret += elem.nodeValue; 1390 | 1391 | // Traverse everything else, except comment nodes 1392 | } else if ( elem.nodeType !== 8 ) { 1393 | ret += getText( elem.childNodes ); 1394 | } 1395 | } 1396 | 1397 | return ret; 1398 | }; 1399 | 1400 | //from jquery.js 1401 | function inArray( elem, array ) { 1402 | if ( array.indexOf ) { 1403 | return array.indexOf( elem ); 1404 | } 1405 | 1406 | for ( var i = 0, length = array.length; i < length; i++ ) { 1407 | if ( array[ i ] === elem ) { 1408 | return i; 1409 | } 1410 | } 1411 | 1412 | return -1; 1413 | } 1414 | 1415 | /* 1416 | * Javascript Diff Algorithm 1417 | * By John Resig (http://ejohn.org/) 1418 | * Modified by Chu Alan "sprite" 1419 | * 1420 | * Released under the MIT license. 1421 | * 1422 | * More Info: 1423 | * http://ejohn.org/projects/javascript-diff-algorithm/ 1424 | * 1425 | * Usage: QUnit.diff(expected, actual) 1426 | * 1427 | * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" 1428 | */ 1429 | QUnit.diff = (function() { 1430 | function diff(o, n) { 1431 | var ns = {}; 1432 | var os = {}; 1433 | 1434 | for (var i = 0; i < n.length; i++) { 1435 | if (ns[n[i]] == null) 1436 | ns[n[i]] = { 1437 | rows: [], 1438 | o: null 1439 | }; 1440 | ns[n[i]].rows.push(i); 1441 | } 1442 | 1443 | for (var i = 0; i < o.length; i++) { 1444 | if (os[o[i]] == null) 1445 | os[o[i]] = { 1446 | rows: [], 1447 | n: null 1448 | }; 1449 | os[o[i]].rows.push(i); 1450 | } 1451 | 1452 | for (var i in ns) { 1453 | if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { 1454 | n[ns[i].rows[0]] = { 1455 | text: n[ns[i].rows[0]], 1456 | row: os[i].rows[0] 1457 | }; 1458 | o[os[i].rows[0]] = { 1459 | text: o[os[i].rows[0]], 1460 | row: ns[i].rows[0] 1461 | }; 1462 | } 1463 | } 1464 | 1465 | for (var i = 0; i < n.length - 1; i++) { 1466 | if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && 1467 | n[i + 1] == o[n[i].row + 1]) { 1468 | n[i + 1] = { 1469 | text: n[i + 1], 1470 | row: n[i].row + 1 1471 | }; 1472 | o[n[i].row + 1] = { 1473 | text: o[n[i].row + 1], 1474 | row: i + 1 1475 | }; 1476 | } 1477 | } 1478 | 1479 | for (var i = n.length - 1; i > 0; i--) { 1480 | if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && 1481 | n[i - 1] == o[n[i].row - 1]) { 1482 | n[i - 1] = { 1483 | text: n[i - 1], 1484 | row: n[i].row - 1 1485 | }; 1486 | o[n[i].row - 1] = { 1487 | text: o[n[i].row - 1], 1488 | row: i - 1 1489 | }; 1490 | } 1491 | } 1492 | 1493 | return { 1494 | o: o, 1495 | n: n 1496 | }; 1497 | } 1498 | 1499 | return function(o, n) { 1500 | o = o.replace(/\s+$/, ''); 1501 | n = n.replace(/\s+$/, ''); 1502 | var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); 1503 | 1504 | var str = ""; 1505 | 1506 | var oSpace = o.match(/\s+/g); 1507 | if (oSpace == null) { 1508 | oSpace = [" "]; 1509 | } 1510 | else { 1511 | oSpace.push(" "); 1512 | } 1513 | var nSpace = n.match(/\s+/g); 1514 | if (nSpace == null) { 1515 | nSpace = [" "]; 1516 | } 1517 | else { 1518 | nSpace.push(" "); 1519 | } 1520 | 1521 | if (out.n.length == 0) { 1522 | for (var i = 0; i < out.o.length; i++) { 1523 | str += '' + out.o[i] + oSpace[i] + ""; 1524 | } 1525 | } 1526 | else { 1527 | if (out.n[0].text == null) { 1528 | for (n = 0; n < out.o.length && out.o[n].text == null; n++) { 1529 | str += '' + out.o[n] + oSpace[n] + ""; 1530 | } 1531 | } 1532 | 1533 | for (var i = 0; i < out.n.length; i++) { 1534 | if (out.n[i].text == null) { 1535 | str += '' + out.n[i] + nSpace[i] + ""; 1536 | } 1537 | else { 1538 | var pre = ""; 1539 | 1540 | for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { 1541 | pre += '' + out.o[n] + oSpace[n] + ""; 1542 | } 1543 | str += " " + out.n[i].text + nSpace[i] + pre; 1544 | } 1545 | } 1546 | } 1547 | 1548 | return str; 1549 | }; 1550 | })(); 1551 | 1552 | })(this); 1553 | -------------------------------------------------------------------------------- /test/jquery-1.6.4.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery v1.6.4 http://jquery.com/ | http://jquery.org/license */ 2 | (function(a,b){function cu(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cr(a){if(!cg[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ch||(ch=c.createElement("iframe"),ch.frameBorder=ch.width=ch.height=0),b.appendChild(ch);if(!ci||!ch.createElement)ci=(ch.contentWindow||ch.contentDocument).document,ci.write((c.compatMode==="CSS1Compat"?"":"")+""),ci.close();d=ci.createElement(a),ci.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ch)}cg[a]=e}return cg[a]}function cq(a,b){var c={};f.each(cm.concat.apply([],cm.slice(0,b)),function(){c[this]=a});return c}function cp(){cn=b}function co(){setTimeout(cp,0);return cn=f.now()}function cf(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ce(){try{return new a.XMLHttpRequest}catch(b){}}function b$(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){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bv(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function bl(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bd,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bk(a){f.nodeName(a,"input")?bj(a):"getElementsByTagName"in a&&f.grep(a.getElementsByTagName("input"),bj)}function bj(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bi(a){return"getElementsByTagName"in a?a.getElementsByTagName("*"):"querySelectorAll"in a?a.querySelectorAll("*"):[]}function bh(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bg(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c=f.expando,d=f.data(a),e=f.data(b,d);if(d=d[c]){var g=d.events;e=e[c]=f.extend({},d);if(g){delete e.handle,e.events={};for(var h in g)for(var i=0,j=g[h].length;i=0===c})}function U(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function M(a,b){return(a&&a!=="*"?a+".":"")+b.replace(y,"`").replace(z,"&")}function L(a){var b,c,d,e,g,h,i,j,k,l,m,n,o,p=[],q=[],r=f._data(this,"events");if(!(a.liveFired===this||!r||!r.live||a.target.disabled||a.button&&a.type==="click")){a.namespace&&(n=new RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)")),a.liveFired=this;var s=r.live.slice(0);for(i=0;ic)break;a.currentTarget=e.elem,a.data=e.handleObj.data,a.handleObj=e.handleObj,o=e.handleObj.origHandler.apply(e.elem,arguments);if(o===!1||a.isPropagationStopped()){c=e.level,o===!1&&(b=!1);if(a.isImmediatePropagationStopped())break}}return b}}function J(a,c,d){var e=f.extend({},d[0]);e.type=a,e.originalEvent={},e.liveFired=b,f.event.handle.call(c,e),e.isDefaultPrevented()&&d[0].preventDefault()}function D(){return!0}function C(){return!1}function m(a,c,d){var e=c+"defer",g=c+"queue",h=c+"mark",i=f.data(a,e,b,!0);i&&(d==="queue"||!f.data(a,g,b,!0))&&(d==="mark"||!f.data(a,h,b,!0))&&setTimeout(function(){!f.data(a,g,b,!0)&&!f.data(a,h,b,!0)&&(f.removeData(a,e,!0),i.resolve())},0)}function l(a){for(var b in a)if(b!=="toJSON")return!1;return!0}function k(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(j,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNaN(d)?i.test(d)?f.parseJSON(d):d:parseFloat(d)}catch(g){}f.data(a,c,d)}else d=b}return d}var c=a.document,d=a.navigator,e=a.location,f=function(){function K(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(K,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};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=n.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.6.4",length:0,size:function(){return this.length},toArray:function(){return G.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)?F.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(),B.done(a);return this},eq:function(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(G.apply(this,arguments),"slice",G.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:F,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;B.resolveWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e._Deferred();if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNaN:function(a){return a==null||!m.test(a)||isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw 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(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){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(x,"ms-").replace(w,y)},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?h.call(arguments,0):c,--e||g.resolveWith(g,h.call(b,0))}}var b=arguments,c=0,d=b.length,e=d,g=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred();if(d>1){for(;c
      a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.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:a.className!=="t",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.firstChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-1000px",top:"-1000px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
      ",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
      t
      ",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0),o.innerHTML="",n.removeChild(o);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var i=/^(?:\{.*\}|\[.*\])$/,j=/([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&&!l(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i=f.expando,j=typeof c=="string",k=a.nodeType,l=k?f.cache:a,m=k?a[f.expando]:a[f.expando]&&f.expando;if((!m||e&&m&&l[m]&&!l[m][i])&&j&&d===b)return;m||(k?a[f.expando]=m=++f.uuid:m=f.expando),l[m]||(l[m]={},k||(l[m].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?l[m][i]=f.extend(l[m][i],c):l[m]=f.extend(l[m],c);g=l[m],e&&(g[i]||(g[i]={}),g=g[i]),d!==b&&(g[f.camelCase(c)]=d);if(c==="events"&&!g[c])return g[i]&&g[i].events;j?(h=g[c],h==null&&(h=g[f.camelCase(c)])):h=g;return h}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e=f.expando,g=a.nodeType,h=g?f.cache:a,i=g?a[f.expando]:f.expando;if(!h[i])return;if(b){d=c?h[i][e]:h[i];if(d){d[b]||(b=f.camelCase(b)),delete d[b];if(!l(d))return}}if(c){delete h[i][e];if(!l(h[i]))return}var j=h[i][e];f.support.deleteExpando||!h.setInterval?delete h[i]:h[i]=null,j?(h[i]={},g||(h[i].toJSON=f.noop),h[i][e]=j):g&&(f.support.deleteExpando?delete a[f.expando]:a.removeAttribute?a.removeAttribute(f.expando):a[f.expando]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d=null;if(typeof a=="undefined"){if(this.length){d=f.data(this[0]);if(this[0].nodeType===1){var e=this[0].attributes,g;for(var h=0,i=e.length;h-1)return!0;return!1},val:function(a){var c,d,e=this[0];if(!arguments.length){if(e){c=f.valHooks[e.nodeName.toLowerCase()]||f.valHooks[e.type];if(c&&"get"in c&&(d=c.get(e,"value"))!==b)return d;d=e.value;return typeof d=="string"?d.replace(p,""):d==null?"":d}return b}var g=f.isFunction(a);return this.each(function(d){var e=f(this),h;if(this.nodeType===1){g?h=a.call(this,d,e.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.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),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=a.selectedIndex,d=[],e=a.options,g=a.type==="select-one";if(c<0)return null;for(var h=g?c:0,i=g?c+1:e.length;h=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},attrFix:{tabindex:"tabIndex"},attr:function(a,c,d,e){var g=a.nodeType;if(!a||g===3||g===8||g===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);var h,i,j=g!==1||!f.isXMLDoc(a);j&&(c=f.attrFix[c]||c,i=f.attrHooks[c],i||(t.test(c)?i=v:u&&(i=u)));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(i&&"set"in i&&j&&(h=i.set(a,d,c))!==b)return h;a.setAttribute(c,""+d);return d}if(i&&"get"in i&&j&&(h=i.get(a,c))!==null)return h;h=a.getAttribute(c);return h===null?b:h},removeAttr:function(a,b){var c;a.nodeType===1&&(b=f.attrFix[b]||b,f.attr(a,b,""),a.removeAttribute(b),t.test(b)&&(c=f.propFix[b]||b)in a&&(a[c]=!1))},attrHooks:{type:{set:function(a,b){if(q.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(u&&f.nodeName(a,"button"))return u.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(u&&f.nodeName(a,"button"))return u.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e=a.nodeType;if(!a||e===3||e===8||e===2)return b;var g,h,i=e!==1||!f.isXMLDoc(a);i&&(c=f.propFix[c]||c,h=f.propHooks[c]);return d!==b?h&&"set"in h&&(g=h.set(a,d,c))!==b?g:a[c]=d:h&&"get"in h&&(g=h.get(a,c))!==null?g:a[c]},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):r.test(a.nodeName)||s.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabIndex=f.propHooks.tabIndex,v={get:function(a,c){var d;return f.prop(a,c)===!0||(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},f.support.getSetAttribute||(u=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&d.nodeValue!==""?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})})),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var w=/\.(.*)$/,x=/^(?:textarea|input|select)$/i,y=/\./g,z=/ /g,A=/[^\w\s.|`]/g,B=function(a){return a.replace(A,"\\$&")};f.event={add:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){if(d===!1)d=C;else if(!d)return;var g,h;d.handler&&(g=d,d=g.handler),d.guid||(d.guid=f.guid++);var i=f._data(a);if(!i)return;var j=i.events,k=i.handle;j||(i.events=j={}),k||(i.handle=k=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.handle.apply(k.elem,arguments):b}),k.elem=a,c=c.split(" ");var l,m=0,n;while(l=c[m++]){h=g?f.extend({},g):{handler:d,data:e},l.indexOf(".")>-1?(n=l.split("."),l=n.shift(),h.namespace=n.slice(0).sort().join(".")):(n=[],h.namespace=""),h.type=l,h.guid||(h.guid=d.guid);var o=j[l],p=f.event.special[l]||{};if(!o){o=j[l]=[];if(!p.setup||p.setup.call(a,e,n,k)===!1)a.addEventListener?a.addEventListener(l,k,!1):a.attachEvent&&a.attachEvent("on"+l,k)}p.add&&(p.add.call(a,h),h.handler.guid||(h.handler.guid=d.guid)),o.push(h),f.event.global[l]=!0}a=null}},global:{},remove:function(a,c,d,e){if(a.nodeType!==3&&a.nodeType!==8){d===!1&&(d=C);var g,h,i,j,k=0,l,m,n,o,p,q,r,s=f.hasData(a)&&f._data(a),t=s&&s.events;if(!s||!t)return;c&&c.type&&(d=c.handler,c=c.type);if(!c||typeof c=="string"&&c.charAt(0)==="."){c=c||"";for(h in t)f.event.remove(a,h+c);return}c=c.split(" ");while(h=c[k++]){r=h,q=null,l=h.indexOf(".")<0,m=[],l||(m=h.split("."),h=m.shift(),n=new RegExp("(^|\\.)"+f.map(m.slice(0).sort(),B).join("\\.(?:.*\\.)?")+"(\\.|$)")),p=t[h];if(!p)continue;if(!d){for(j=0;j=0&&(h=h.slice(0,-1),j=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if(!!e&&!f.event.customEvent[h]||!!f.event.global[h]){c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.exclusive=j,c.namespace=i.join("."),c.namespace_re=new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)");if(g||!e)c.preventDefault(),c.stopPropagation();if(!e){f.each(f.cache,function(){var a=f.expando,b=this[a];b&&b.events&&b.events[h]&&f.event.trigger(c,d,b.handle.elem)});return}if(e.nodeType===3||e.nodeType===8)return;c.result=b,c.target=e,d=d!=null?f.makeArray(d):[],d.unshift(c);var k=e,l=h.indexOf(":")<0?"on"+h:"";do{var m=f._data(k,"handle");c.currentTarget=k,m&&m.apply(k,d),l&&f.acceptData(k)&&k[l]&&k[l].apply(k,d)===!1&&(c.result=!1,c.preventDefault()),k=k.parentNode||k.ownerDocument||k===c.target.ownerDocument&&a}while(k&&!c.isPropagationStopped());if(!c.isDefaultPrevented()){var n,o=f.event.special[h]||{};if((!o._default||o._default.call(e.ownerDocument,c)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)){try{l&&e[h]&&(n=e[l],n&&(e[l]=null),f.event.triggered=h,e[h]())}catch(p){}n&&(e[l]=n),f.event.triggered=b}}return c.result}},handle:function(c){c=f.event.fix(c||a.event);var d=((f._data(this,"events")||{})[c.type]||[]).slice(0),e=!c.exclusive&&!c.namespace,g=Array.prototype.slice.call(arguments,0);g[0]=c,c.currentTarget=this;for(var h=0,i=d.length;h-1?f.map(a.options,function(a){return a.selected}).join("-"):"":f.nodeName(a,"select")&&(c=a.selectedIndex);return c},I=function(c){var d=c.target,e,g;if(!!x.test(d.nodeName)&&!d.readOnly){e=f._data(d,"_change_data"),g=H(d),(c.type!=="focusout"||d.type!=="radio")&&f._data(d,"_change_data",g);if(e===b||g===e)return;if(e!=null||g)c.type="change",c.liveFired=b,f.event.trigger(c,arguments[1],d)}};f.event.special.change={filters:{focusout:I,beforedeactivate:I,click:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(c==="radio"||c==="checkbox"||f.nodeName(b,"select"))&&I.call(this,a)},keydown:function(a){var b=a.target,c=f.nodeName(b,"input")?b.type:"";(a.keyCode===13&&!f.nodeName(b,"textarea")||a.keyCode===32&&(c==="checkbox"||c==="radio")||c==="select-multiple")&&I.call(this,a)},beforeactivate:function(a){var b=a.target;f._data(b,"_change_data",H(b))}},setup:function(a,b){if(this.type==="file")return!1;for(var c in G)f.event.add(this,c+".specialChange",G[c]);return x.test(this.nodeName)},teardown:function(a){f.event.remove(this,".specialChange");return x.test(this.nodeName)}},G=f.event.special.change.filters,G.focus=G.beforeactivate}f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){function e(a){var c=f.event.fix(a);c.type=b,c.originalEvent={},f.event.trigger(c,null,c.target),c.isDefaultPrevented()&&a.preventDefault()}var d=0;f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.each(["bind","one"],function(a,c){f.fn[c]=function(a,d,e){var g;if(typeof a=="object"){for(var h in a)this[c](h,d,a[h],e);return this}if(arguments.length===2||d===!1)e=d,d=b;c==="one"?(g=function(a){f(this).unbind(a,g);return e.apply(this,arguments)},g.guid=e.guid||f.guid++):g=e;if(a==="unload"&&c!=="one")this.one(a,d,e);else for(var i=0,j=this.length;i0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0)}),function(){function u(a,b,c,d,e,f){for(var g=0,h=d.length;g0){j=i;break}}i=i[a]}d[g]=j}}}function t(a,b,c,d,e,f){for(var g=0,h=d.length;g+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d=0,e=Object.prototype.toString,g=!1,h=!0,i=/\\/g,j=/\W/;[0,0].sort(function(){h=!1;return 0});var k=function(b,d,f,g){f=f||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return f;var i,j,n,o,q,r,s,t,u=!0,w=k.isXML(d),x=[],y=b;do{a.exec(""),i=a.exec(y);if(i){y=i[3],x.push(i[1]);if(i[2]){o=i[3];break}}}while(i);if(x.length>1&&m.exec(b))if(x.length===2&&l.relative[x[0]])j=v(x[0]+x[1],d);else{j=l.relative[x[0]]?[d]:k(x.shift(),d);while(x.length)b=x.shift(),l.relative[b]&&(b+=x.shift()),j=v(b,j)}else{!g&&x.length>1&&d.nodeType===9&&!w&&l.match.ID.test(x[0])&&!l.match.ID.test(x[x.length-1])&&(q=k.find(x.shift(),d,w),d=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]);if(d){q=g?{expr:x.pop(),set:p(g)}:k.find(x.pop(),x.length===1&&(x[0]==="~"||x[0]==="+")&&d.parentNode?d.parentNode:d,w),j=q.expr?k.filter(q.expr,q.set):q.set,x.length>0?n=p(j):u=!1;while(x.length)r=x.pop(),s=r,l.relative[r]?s=x.pop():r="",s==null&&(s=d),l.relative[r](n,s,w)}else n=x=[]}n||(n=j),n||k.error(r||b);if(e.call(n)==="[object Array]")if(!u)f.push.apply(f,n);else if(d&&d.nodeType===1)for(t=0;n[t]!=null;t++)n[t]&&(n[t]===!0||n[t].nodeType===1&&k.contains(d,n[t]))&&f.push(j[t]);else for(t=0;n[t]!=null;t++)n[t]&&n[t].nodeType===1&&f.push(j[t]);else p(n,f);o&&(k(o,h,f,g),k.uniqueSort(f));return f};k.uniqueSort=function(a){if(r){g=h,a.sort(r);if(g)for(var b=1;b0},k.find=function(a,b,c){var d;if(!a)return[];for(var e=0,f=l.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!j.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(i,"")},TAG:function(a,b){return a[1].replace(i,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||k.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]&&k.error(a[0]);a[0]=d++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(i,"");!f&&l.attrMap[g]&&(a[1]=l.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(i,""),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]=k(b[3],null,null,c);else{var g=k.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(l.match.POS.test(b[0])||l.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!!k(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=l.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||k.getText([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.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=l.attrHandle[c]?l.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":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=l.setFilters[e];if(f)return f(a,c,b,d)}}},m=l.match.POS,n=function(a,b){return"\\"+(b-0+1)};for(var o in l.match)l.match[o]=new RegExp(l.match[o].source+/(?![^\[]*\])(?![^\(]*\))/.source),l.leftMatch[o]=new RegExp(/(^(?:.|\r|\n)*?)/.source+l.match[o].source.replace(/\\(\d+)/g,n));var p=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(q){p=function(a,b){var c=0,d=b||[];if(e.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var f=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(l.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:[]}},l.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&&(l.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")!=="#"&&(l.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=k,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

      ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){k=function(b,e,f,g){e=e||c;if(!g&&!k.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return p(e.getElementsByTagName(b),f);if(h[2]&&l.find.CLASS&&e.getElementsByClassName)return p(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return p([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return p([],f);if(i.id===h[3])return p([i],f)}try{return p(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var m=e,n=e.getAttribute("id"),o=n||d,q=e.parentNode,r=/^\s*[+~]/.test(b);n?o=o.replace(/'/g,"\\$&"):e.setAttribute("id",o),r&&q&&(e=e.parentNode);try{if(!r||q)return p(e.querySelectorAll("[id='"+o+"'] "+b),f)}catch(s){}finally{n||m.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)k[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}k.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(a))try{if(e||!l.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 k(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;l.order.splice(1,0,"CLASS"),l.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?k.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?k.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:k.contains=function(){return!1},k.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var v=function(a,b){var c,d=[],e="",f=b.nodeType?[b]:b;while(c=l.match.PSEUDO.exec(a))e+=c[0],a=a.replace(l.match.PSEUDO,"");a=l.relative[a]?a+"*":a;for(var g=0,h=f.length;g0)for(h=g;h0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h,i,j={},k=1;if(g&&a.length){for(d=0,e=a.length;d-1:f(g).is(h))&&c.push({selector:i,elem:g,level:k});g=g.parentNode,k++}}return c}var l=S.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;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(U(c[0])||U(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),g=R.call(arguments);N.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!T[a]?f.unique(e):e,(this.length>1||P.test(d))&&O.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.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 W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/",""],legend:[1,"
      ","
      "],thead:[1,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],col:[2,"","
      "],area:[1,"",""],_default:[0,"",""]};be.optgroup=be.option,be.tbody=be.tfoot=be.colgroup=be.caption=be.thead,be.th=be.td,f.support.htmlSerialize||(be._default=[1,"div
      ","
      "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},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){return this.each(function(){f(this).wrapAll(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(arguments[0]);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(arguments[0]).toArray());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){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!be[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1>");try{for(var c=0,d=this.length;c1&&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=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bh(a,d),e=bi(a),g=bi(d);for(h=0;e[h];++h)g[h]&&bh(e[h],g[h])}if(b){bg(a,d);if(c){e=bi(a),g=bi(d);for(h=0;e[h];++h)bg(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=be[l]||be._default,n=m[0],o=b.createElement("div");o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bn.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.isNaN(b)?"":"alpha(opacity="+b*100+")",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bm,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bm.test(g)?g.replace(bm,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bv(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bw=function(a,c){var d,e,g;c=c.replace(bo,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bx=function(a,b){var c,d=a.currentStyle&&a.currentStyle[b],e=a.runtimeStyle&&a.runtimeStyle[b],f=a.style;!bp.test(d)&&bq.test(d)&&(c=f.left,e&&(a.runtimeStyle.left=a.currentStyle.left),f.left=b==="fontSize"?"1em":d||0,d=f.pixelLeft+"px",f.left=c,e&&(a.runtimeStyle.left=e));return d===""?"auto":d}),bv=bw||bx,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.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bz=/%20/g,bA=/\[\]$/,bB=/\r?\n/g,bC=/#.*$/,bD=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bE=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bF=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bG=/^(?:GET|HEAD)$/,bH=/^\/\//,bI=/\?/,bJ=/)<[^<]*)*<\/script>/gi,bK=/^(?:select|textarea)/i,bL=/\s+/,bM=/([?&])_=[^&]*/,bN=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bO=f.fn.load,bP={},bQ={},bR,bS,bT=["*/"]+["*"];try{bR=e.href}catch(bU){bR=c.createElement("a"),bR.href="",bR=bR.href}bS=bN.exec(bR.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bO)return bO.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(bJ,"")).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||bK.test(this.nodeName)||bE.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(bB,"\r\n")}}):{name:b.name,value:c.replace(bB,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(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?bX(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),bX(a,b);return a},ajaxSettings:{url:bR,isLocal:bF.test(bS[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bT},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:bV(bP),ajaxTransport:bV(bQ),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?bZ(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=b$(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.resolveWith(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._Deferred(),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=bD.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.done,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(bC,"").replace(bH,bS[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bL),d.crossDomain==null&&(r=bN.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bS[1]&&r[2]==bS[2]&&(r[3]||(r[1]==="http:"?80:443))==(bS[3]||(bS[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bW(bP,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bG.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bI.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bM,"$1_="+x);d.url=y+(y===d.url?(bI.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]!=="*"?", "+bT+"; 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=bW(bQ,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){s<2?w(-1,z):f.error(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)bY(g,a[g],c,e);return d.join("&").replace(bz,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var b_=f.now(),ca=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+b_++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ca.test(b.url)||e&&ca.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(ca,l),b.url===j&&(e&&(k=k.replace(ca,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 cb=a.ActiveXObject?function(){for(var a in cd)cd[a](0,1)}:!1,cc=0,cd;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ce()||cf()}:ce,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,cb&&delete cd[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),m.text=h.responseText;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=++cc,cb&&(cd||(cd={},f(a).unload(cb)),cd[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cg={},ch,ci,cj=/^(?:toggle|show|hide)$/,ck=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cl,cm=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cn;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cq("show",3),a,b,c);for(var g=0,h=this.length;g=e.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),e.animatedProperties[this.prop]=!0;for(g in e.animatedProperties)e.animatedProperties[g]!==!0&&(c=!1);if(c){e.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){d.style["overflow"+b]=e.overflow[a]}),e.hide&&f(d).hide();if(e.hide||e.show)for(var i in e.animatedProperties)f.style(d,i,e.orig[i]);e.complete.call(d)}return!1}e.duration==Infinity?this.now=b:(h=b-this.startTime,this.state=h/e.duration,this.pos=f.easing[e.animatedProperties[this.prop]](this.state,h,0,1,e.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){for(var a=f.timers,b=0;b
      ";f.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"}),b.innerHTML=j,a.insertBefore(b,a.firstChild),d=b.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,this.doesNotAddBorder=e.offsetTop!==5,this.doesAddBorderForTableAndCells=h.offsetTop===5,e.style.position="fixed",e.style.top="20px",this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==i,a.removeChild(b),f.offset.initialize=f.noop},bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.offset.initialize(),f.offset.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-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=ct.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&&!ct.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cu(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cu(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a&&a.style?parseFloat(f.css(a,d,"padding")):null},f.fn["outer"+c]=function(a){var b=this[0];return b&&b.style?parseFloat(f.css(b,d,a?"margin":"border")):null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNaN(j)?i:j}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); --------------------------------------------------------------------------------