Skip to content
Browse files

Initial commit

  • Loading branch information...
0 parents commit d01eafd46a288d53101b0924b92a44f56b7dd213 Kevin Malakoff committed Nov 18, 2011
Showing with 4,096 additions and 0 deletions.
  1. +18 −0 .gitignore
  2. +22 −0 LICENSE
  3. +38 −0 README.md
  4. +45 −0 Rakefile
  5. +186 −0 docs/docco.css
  6. +44 −0 docs/jsl.conf
  7. +98 −0 docs/lifecycle.html
  8. +9 −0 lifecycle-min.js
  9. +112 −0 lifecycle.js
  10. +12 −0 package.json
  11. +30 −0 test/test.html
  12. +237 −0 test/test.js
  13. +19 −0 test/vendor/qunit/jquery.js
  14. +670 −0 test/vendor/qunit/jslitmus.js
  15. +196 −0 test/vendor/qunit/qunit.css
  16. +2,360 −0 test/vendor/qunit/qunit.js
18 .gitignore
@@ -0,0 +1,18 @@
+# osx noise
+.DS_Store
+profile
+
+# xcode noise
+build/*
+*.mode1
+*.mode1v3
+*.mode2v3
+*.perspective
+*.perspectivev3
+*.pbxuser
+*.xcworkspace
+xcuserdata
+
+# svn & cvs
+.svn
+CVS
22 LICENSE
@@ -0,0 +1,22 @@
+Copyright (c) 2011 Kevin Malakoff
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
38 README.md
@@ -0,0 +1,38 @@
+````
+Lifecycle.js provides conventions and helpers to manage the life cycles of Javascript instances.
+````
+
+## LC.own/LC.disown
+Handles individual objects, arrays, and object properties that comply with some lifecycle conventions:
+
+* clone() and destroy()
+* retain() and release()
+* clone() and Javascript memory management
+* plain old JSON
+
+### Examples:
+
+```javascript
+var an_object = new Object(); var owned_copy_object = LC.own(an_object); LC.disown(an_object);
+var an_array = [new Object(), ‘hello’, new Object()]; var owned_copy_array = LC.own(an_array); LC.disown(an_array);
+var an_object = {one: new Object(), two: new Object(), three: ‘there’}; var owned_copy_object = LC.own(an_object, {properties:true}); LC.disown(an_object);
+```
+
+## LC.RefCountable
+Very basic class (following Coffeescript construction) for a reference countable class.
+
+### Examples:
+
+```coffeescript
+class MyClass extends LC.RefCountable
+ constructor: ->
+ super
+ @is_alive = true
+ _destroy: ->
+ @is_alive = false
+
+instance = new MyClass() # ref_count = 1
+instance.retain() # ref_count = 2
+instance.release() # ref_count = 1
+instance.release() # ref_count = 0 and _destroy() called
+```
45 Rakefile
@@ -0,0 +1,45 @@
+require 'rubygems'
+require 'closure-compiler'
+
+HEADER = /((^\s*\/\/.*\n)+)/
+def minimize_with_header(source_filename, destination_filename)
+ source = File.read(source_filename)
+ header = source.match(HEADER)
+ min = Closure::Compiler.new.compress(source)
+ File.open(destination_filename, 'w') do |file|
+ file.write header[1].squeeze(' ') + min
+ end
+end
+
+# Check for the existence of an executable.
+def check(exec, name, url)
+ return unless `which #{exec}`.empty?
+ puts "#{name} not found.\nInstall it from #{url}"
+ exit
+end
+
+desc "Use the Closure Compiler to compress Lifecycle.js"
+task :build do
+ minimize_with_header('lifecycle.js', 'lifecycle-min.js')
+end
+
+desc "check, build and generate documentation"
+task :package do
+ begin
+ system "jsl -nofilelisting -nologo -conf docs/jsl.conf -process lifecycle.js"
+ minimize_with_header('lifecycle.js', 'lifecycle-min.js')
+ check 'docco', 'docco', 'https://github.com/jashkenas/docco'
+ sh "docco lifecycle.js"
+ end
+end
+
+desc "Build the docco documentation"
+task :doc do
+ check 'docco', 'docco', 'https://github.com/jashkenas/docco'
+ sh "docco lifecycle.js"
+end
+
+desc "run JavaScriptLint on the source"
+task :lint do
+ system "jsl -nofilelisting -nologo -conf docs/jsl.conf -process lifecycle.js"
+end
186 docs/docco.css
@@ -0,0 +1,186 @@
+/*--------------------- Layout and Typography ----------------------------*/
+body {
+ font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
+ font-size: 15px;
+ line-height: 22px;
+ color: #252519;
+ margin: 0; padding: 0;
+}
+a {
+ color: #261a3b;
+}
+ a:visited {
+ color: #261a3b;
+ }
+p {
+ margin: 0 0 15px 0;
+}
+h1, h2, h3, h4, h5, h6 {
+ margin: 0px 0 15px 0;
+}
+ h1 {
+ margin-top: 40px;
+ }
+#container {
+ position: relative;
+}
+#background {
+ position: fixed;
+ top: 0; left: 525px; right: 0; bottom: 0;
+ background: #f5f5ff;
+ border-left: 1px solid #e5e5ee;
+ z-index: -1;
+}
+#jump_to, #jump_page {
+ background: white;
+ -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
+ -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
+ font: 10px Arial;
+ text-transform: uppercase;
+ cursor: pointer;
+ text-align: right;
+}
+#jump_to, #jump_wrapper {
+ position: fixed;
+ right: 0; top: 0;
+ padding: 5px 10px;
+}
+ #jump_wrapper {
+ padding: 0;
+ display: none;
+ }
+ #jump_to:hover #jump_wrapper {
+ display: block;
+ }
+ #jump_page {
+ padding: 5px 0 3px;
+ margin: 0 0 25px 25px;
+ }
+ #jump_page .source {
+ display: block;
+ padding: 5px 10px;
+ text-decoration: none;
+ border-top: 1px solid #eee;
+ }
+ #jump_page .source:hover {
+ background: #f5f5ff;
+ }
+ #jump_page .source:first-child {
+ }
+table td {
+ border: 0;
+ outline: 0;
+}
+ td.docs, th.docs {
+ max-width: 450px;
+ min-width: 450px;
+ min-height: 5px;
+ padding: 10px 25px 1px 50px;
+ overflow-x: hidden;
+ vertical-align: top;
+ text-align: left;
+ }
+ .docs pre {
+ margin: 15px 0 15px;
+ padding-left: 15px;
+ }
+ .docs p tt, .docs p code {
+ background: #f8f8ff;
+ border: 1px solid #dedede;
+ font-size: 12px;
+ padding: 0 0.2em;
+ }
+ .pilwrap {
+ position: relative;
+ }
+ .pilcrow {
+ font: 12px Arial;
+ text-decoration: none;
+ color: #454545;
+ position: absolute;
+ top: 3px; left: -20px;
+ padding: 1px 2px;
+ opacity: 0;
+ -webkit-transition: opacity 0.2s linear;
+ }
+ td.docs:hover .pilcrow {
+ opacity: 1;
+ }
+ td.code, th.code {
+ padding: 14px 15px 16px 25px;
+ width: 100%;
+ vertical-align: top;
+ background: #f5f5ff;
+ border-left: 1px solid #e5e5ee;
+ }
+ pre, tt, code {
+ font-size: 12px; line-height: 18px;
+ font-family: Monaco, Consolas, "Lucida Console", monospace;
+ margin: 0; padding: 0;
+ }
+
+
+/*---------------------- Syntax Highlighting -----------------------------*/
+td.linenos { background-color: #f0f0f0; padding-right: 10px; }
+span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
+body .hll { background-color: #ffffcc }
+body .c { color: #408080; font-style: italic } /* Comment */
+body .err { border: 1px solid #FF0000 } /* Error */
+body .k { color: #954121 } /* Keyword */
+body .o { color: #666666 } /* Operator */
+body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
+body .cp { color: #BC7A00 } /* Comment.Preproc */
+body .c1 { color: #408080; font-style: italic } /* Comment.Single */
+body .cs { color: #408080; font-style: italic } /* Comment.Special */
+body .gd { color: #A00000 } /* Generic.Deleted */
+body .ge { font-style: italic } /* Generic.Emph */
+body .gr { color: #FF0000 } /* Generic.Error */
+body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
+body .gi { color: #00A000 } /* Generic.Inserted */
+body .go { color: #808080 } /* Generic.Output */
+body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
+body .gs { font-weight: bold } /* Generic.Strong */
+body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
+body .gt { color: #0040D0 } /* Generic.Traceback */
+body .kc { color: #954121 } /* Keyword.Constant */
+body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
+body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
+body .kp { color: #954121 } /* Keyword.Pseudo */
+body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
+body .kt { color: #B00040 } /* Keyword.Type */
+body .m { color: #666666 } /* Literal.Number */
+body .s { color: #219161 } /* Literal.String */
+body .na { color: #7D9029 } /* Name.Attribute */
+body .nb { color: #954121 } /* Name.Builtin */
+body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
+body .no { color: #880000 } /* Name.Constant */
+body .nd { color: #AA22FF } /* Name.Decorator */
+body .ni { color: #999999; font-weight: bold } /* Name.Entity */
+body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
+body .nf { color: #0000FF } /* Name.Function */
+body .nl { color: #A0A000 } /* Name.Label */
+body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
+body .nt { color: #954121; font-weight: bold } /* Name.Tag */
+body .nv { color: #19469D } /* Name.Variable */
+body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
+body .w { color: #bbbbbb } /* Text.Whitespace */
+body .mf { color: #666666 } /* Literal.Number.Float */
+body .mh { color: #666666 } /* Literal.Number.Hex */
+body .mi { color: #666666 } /* Literal.Number.Integer */
+body .mo { color: #666666 } /* Literal.Number.Oct */
+body .sb { color: #219161 } /* Literal.String.Backtick */
+body .sc { color: #219161 } /* Literal.String.Char */
+body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
+body .s2 { color: #219161 } /* Literal.String.Double */
+body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
+body .sh { color: #219161 } /* Literal.String.Heredoc */
+body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
+body .sx { color: #954121 } /* Literal.String.Other */
+body .sr { color: #BB6688 } /* Literal.String.Regex */
+body .s1 { color: #219161 } /* Literal.String.Single */
+body .ss { color: #19469D } /* Literal.String.Symbol */
+body .bp { color: #954121 } /* Name.Builtin.Pseudo */
+body .vc { color: #19469D } /* Name.Variable.Class */
+body .vg { color: #19469D } /* Name.Variable.Global */
+body .vi { color: #19469D } /* Name.Variable.Instance */
+body .il { color: #666666 } /* Literal.Number.Integer.Long */
44 docs/jsl.conf
@@ -0,0 +1,44 @@
+# JavaScriptLint configuration file for CoffeeScript.
+
++no_return_value # function {0} does not always return a value
++duplicate_formal # duplicate formal argument {0}
+-equal_as_assign # test for equality (==) mistyped as assignment (=)?{0}
++var_hides_arg # variable {0} hides argument
++redeclared_var # redeclaration of {0} {1}
+-anon_no_return_value # anonymous function does not always return a value
++missing_semicolon # missing semicolon
++meaningless_block # meaningless block; curly braces have no impact
+-comma_separated_stmts # multiple statements separated by commas (use semicolons?)
++unreachable_code # unreachable code
++missing_break # missing break statement
++missing_break_for_last_case # missing break statement for last case in switch
+-comparison_type_conv # comparisons against null, 0, true, false, or an empty string allowing implicit type conversion (use === or !==)
+-inc_dec_within_stmt # increment (++) and decrement (--) operators used as part of greater statement
+-useless_void # use of the void type may be unnecessary (void is always undefined)
++multiple_plus_minus # unknown order of operations for successive plus (e.g. x+++y) or minus (e.g. x---y) signs
++use_of_label # use of label
+-block_without_braces # block statement without curly braces
++leading_decimal_point # leading decimal point may indicate a number or an object member
++trailing_decimal_point # trailing decimal point may indicate a number or an object member
++octal_number # leading zeros make an octal number
++nested_comment # nested comment
++misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma
++ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement
++empty_statement # empty statement or extra semicolon
+-missing_option_explicit # the "option explicit" control comment is missing
++partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag
++dup_option_explicit # duplicate "option explicit" control comment
++useless_assign # useless assignment
++ambiguous_nested_stmt # block statements containing block statements should use curly braces to resolve ambiguity
++ambiguous_else_stmt # the else statement could be matched with one of multiple if statements (use curly braces to indicate intent)
+-missing_default_case # missing default case in switch statement
++duplicate_case_in_switch # duplicate case in switch statements
++default_not_at_end # the default case is not at the end of the switch statement
++legacy_cc_not_understood # couldn't understand control comment using /*@keyword@*/ syntax
++jsl_cc_not_understood # couldn't understand control comment using /*jsl:keyword*/ syntax
++useless_comparison # useless comparison; comparing identical expressions
++with_statement # with statement hides undeclared variables; use temporary variable instead
++trailing_comma_in_array # extra comma is not recommended in array initializers
++assign_to_function_call # assignment to a function call
++parseint_missing_radix # parseInt missing radix parameter
++lambda_assign_requires_semicolon
98 docs/lifecycle.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html> <html> <head> <title>lifecycle.js</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> lifecycle.js </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> <p>Lifecycle.js 1.0.0
+(c) 2011 Kevin Malakoff.
+Lifecycle is freely distributable under the MIT license.
+https://github.com/kmalakoff/Lifecycle</p> </td> <td class="code"> <div class="highlight"><pre><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
+
+<span class="k">this</span><span class="p">.</span><span class="nx">Lifecyle</span> <span class="o">||</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">Lifecyle</span> <span class="o">=</span> <span class="p">{});</span>
+<span class="k">this</span><span class="p">.</span><span class="nx">LC</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">Lifecyle</span><span class="p">;</span>
+<span class="nx">LC</span><span class="p">.</span><span class="nx">VERSION</span> <span class="o">=</span> <span class="s1">&#39;1.0.0&#39;</span><span class="p">;</span></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <p>//////////////HELPERS - BEGIN//////////////////</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">isArray</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">return</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">constructor</span> <span class="o">==</span> <span class="nb">Array</span><span class="p">;</span>
+<span class="p">};</span></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <p>//////////////HELPERS - END//////////////////</p> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <p>Deduces the type of ownership of an item and if available, it retains it (reference counted) or clones it.
+<br/><strong>Options:</strong><br/>
+* <code>properties</code> - used to disambigate between owning an object and owning each property.<br/>
+* <code>share_collection</code> - used to disambigate between owning a collection's items (share) and cloning a collection (don't share).
+* <code>prefer_clone</code> - used to disambigate when both retain and clone exist. By default retain is prefered (eg. sharing for lower memory footprint).</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">LC</span><span class="p">.</span><span class="nx">own</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">obj</span> <span class="o">||</span> <span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span><span class="o">!=</span><span class="s1">&#39;object&#39;</span><span class="p">))</span> <span class="k">return</span> <span class="nx">obj</span><span class="p">;</span>
+ <span class="nx">options</span> <span class="o">||</span> <span class="p">(</span><span class="nx">options</span> <span class="o">=</span> <span class="p">{});</span>
+ <span class="k">if</span> <span class="p">(</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">obj</span><span class="p">))</span> <span class="p">{</span>
+ <span class="kd">var</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">l</span> <span class="o">=</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span>
+ <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">share_collection</span><span class="p">)</span> <span class="p">{</span> <span class="k">for</span> <span class="p">(</span><span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nx">i</span><span class="o">&lt;</span><span class="nx">l</span><span class="p">;</span><span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="nx">LC</span><span class="p">.</span><span class="nx">own</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span> <span class="p">{</span><span class="nx">prefer_clone</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">prefer_clone</span><span class="p">});</span> <span class="p">}</span> <span class="k">return</span> <span class="nx">obj</span><span class="p">;</span> <span class="p">}</span>
+ <span class="k">else</span> <span class="p">{</span>
+ <span class="kd">var</span> <span class="nx">a_clone</span> <span class="o">=</span> <span class="p">[];</span>
+ <span class="k">for</span> <span class="p">(</span><span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nx">i</span><span class="o">&lt;</span><span class="nx">l</span><span class="p">;</span><span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="nx">a_clone</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">LC</span><span class="p">.</span><span class="nx">own</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span> <span class="p">{</span><span class="nx">prefer_clone</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">prefer_clone</span><span class="p">}));</span> <span class="p">}</span>
+ <span class="k">return</span> <span class="nx">a_clone</span><span class="p">;</span>
+ <span class="p">}</span>
+ <span class="p">}</span>
+ <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">properties</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">share_collection</span><span class="p">)</span> <span class="p">{</span> <span class="k">for</span> <span class="p">(</span><span class="nx">key</span> <span class="k">in</span> <span class="nx">obj</span><span class="p">)</span> <span class="p">{</span> <span class="nx">LC</span><span class="p">.</span><span class="nx">own</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">],</span> <span class="p">{</span><span class="nx">prefer_clone</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">prefer_clone</span><span class="p">});</span> <span class="p">}</span> <span class="k">return</span> <span class="nx">obj</span><span class="p">;</span> <span class="p">}</span>
+ <span class="k">else</span> <span class="p">{</span>
+ <span class="kd">var</span> <span class="nx">b_clone</span> <span class="o">=</span> <span class="p">{};</span>
+ <span class="k">for</span> <span class="p">(</span><span class="nx">key</span> <span class="k">in</span> <span class="nx">obj</span><span class="p">)</span> <span class="p">{</span> <span class="nx">b_clone</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span> <span class="o">=</span> <span class="nx">LC</span><span class="p">.</span><span class="nx">own</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">],</span> <span class="p">{</span><span class="nx">prefer_clone</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">prefer_clone</span><span class="p">});</span> <span class="p">}</span>
+ <span class="k">return</span> <span class="nx">b_clone</span><span class="p">;</span>
+ <span class="p">}</span>
+ <span class="p">}</span>
+ <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">retain</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">prefer_clone</span> <span class="o">&amp;&amp;</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">clone</span><span class="p">)</span> <span class="k">return</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">clone</span><span class="p">();</span>
+ <span class="k">else</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">retain</span><span class="p">();</span>
+ <span class="p">}</span>
+ <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">clone</span><span class="p">)</span> <span class="k">return</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">clone</span><span class="p">();</span>
+ <span class="k">return</span> <span class="nx">obj</span><span class="p">;</span>
+<span class="p">};</span></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Deduces the type of ownership of an item and if available, it releases it (reference counted) or destroys it.
+<br/><strong>Options:</strong><br/>
+* <code>properties</code> - used to disambigate between owning an object and owning each property.<br/>
+* <code>clear_values</code> - used to disambigate between clearing disowned items and removing them (by default, they are removed).
+* <code>remove_values</code> - used to indicate that the values should be disowned and removed from the collections.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">LC</span><span class="p">.</span><span class="nx">disown</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">obj</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">obj</span> <span class="o">||</span> <span class="p">(</span><span class="k">typeof</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span><span class="o">!=</span><span class="s1">&#39;object&#39;</span><span class="p">))</span> <span class="k">return</span> <span class="nx">obj</span><span class="p">;</span>
+ <span class="nx">options</span> <span class="o">||</span> <span class="p">(</span><span class="nx">options</span> <span class="o">=</span> <span class="p">{});</span>
+ <span class="k">if</span> <span class="p">(</span><span class="nx">isArray</span><span class="p">(</span><span class="nx">obj</span><span class="p">))</span> <span class="p">{</span>
+ <span class="kd">var</span> <span class="nx">i</span><span class="p">,</span> <span class="nx">l</span> <span class="o">=</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span>
+ <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">clear_values</span><span class="p">)</span> <span class="p">{</span> <span class="k">for</span> <span class="p">(</span><span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nx">i</span><span class="o">&lt;</span><span class="nx">l</span><span class="p">;</span><span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="nx">LC</span><span class="p">.</span><span class="nx">disown</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span> <span class="p">{</span><span class="nx">clear_values</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">clear_values</span><span class="p">});</span> <span class="nx">obj</span><span class="p">[</span><span class="nx">i</span><span class="p">]</span><span class="o">=</span><span class="kc">null</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span>
+ <span class="k">else</span> <span class="p">{</span>
+ <span class="k">for</span> <span class="p">(</span><span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nx">i</span><span class="o">&lt;</span><span class="nx">l</span><span class="p">;</span><span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="nx">LC</span><span class="p">.</span><span class="nx">disown</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span> <span class="p">{</span><span class="nx">remove_values</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">remove_values</span><span class="p">});</span> <span class="p">}</span>
+ <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">remove_values</span><span class="p">)</span> <span class="p">{</span><span class="nx">obj</span><span class="p">.</span><span class="nx">length</span><span class="o">=</span><span class="mi">0</span><span class="p">;}</span>
+ <span class="p">}</span>
+ <span class="k">return</span> <span class="nx">obj</span><span class="p">;</span>
+ <span class="p">}</span>
+ <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">properties</span><span class="p">)</span> <span class="p">{</span>
+ <span class="kd">var</span> <span class="nx">key</span><span class="p">;</span>
+ <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">clear_values</span><span class="p">)</span> <span class="p">{</span> <span class="k">for</span> <span class="p">(</span><span class="nx">key</span> <span class="k">in</span> <span class="nx">obj</span><span class="p">)</span> <span class="p">{</span> <span class="nx">LC</span><span class="p">.</span><span class="nx">disown</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">],</span> <span class="p">{</span><span class="nx">clear_values</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">clear_values</span><span class="p">});</span> <span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">]</span><span class="o">=</span><span class="kc">null</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span>
+ <span class="k">else</span> <span class="p">{</span>
+ <span class="k">for</span> <span class="p">(</span><span class="nx">key</span> <span class="k">in</span> <span class="nx">obj</span><span class="p">)</span> <span class="p">{</span> <span class="nx">LC</span><span class="p">.</span><span class="nx">disown</span><span class="p">(</span><span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">],</span> <span class="p">{</span><span class="nx">remove_values</span><span class="o">:</span> <span class="nx">options</span><span class="p">.</span><span class="nx">remove_values</span><span class="p">});}</span>
+ <span class="k">if</span> <span class="p">(</span><span class="nx">options</span><span class="p">.</span><span class="nx">remove_values</span><span class="p">)</span> <span class="p">{</span><span class="k">for</span><span class="p">(</span><span class="nx">key</span> <span class="k">in</span> <span class="nx">obj</span><span class="p">)</span> <span class="p">{</span> <span class="k">delete</span> <span class="nx">obj</span><span class="p">[</span><span class="nx">key</span><span class="p">];</span> <span class="p">}}</span>
+ <span class="p">}</span>
+ <span class="k">return</span> <span class="nx">obj</span><span class="p">;</span>
+ <span class="p">}</span>
+ <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">release</span><span class="p">)</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">release</span><span class="p">();</span>
+ <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="nx">obj</span><span class="p">.</span><span class="nx">destroy</span><span class="p">)</span> <span class="nx">obj</span><span class="p">.</span><span class="nx">destroy</span><span class="p">();</span>
+ <span class="k">return</span> <span class="nx">obj</span><span class="p">;</span>
+<span class="p">};</span></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <p>A simple reference counting class using Coffeescript class construction.
+Convention: implement a _destroy method with custom cleanup when reference count hits zero.</p> </td> <td class="code"> <div class="highlight"><pre><span class="nx">LC</span><span class="p">.</span><span class="nx">RefCountable</span> <span class="o">=</span> <span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
+ <span class="kd">function</span> <span class="nx">RefCountable</span><span class="p">()</span> <span class="p">{</span>
+ <span class="k">this</span><span class="p">.</span><span class="nx">ref_count</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
+ <span class="p">}</span>
+ <span class="nx">RefCountable</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">retain</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
+ <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">ref_count</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">&quot;LC.RefCounting: ref_count is corrupt: &quot;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">ref_count</span><span class="p">);</span>
+ <span class="p">}</span>
+ <span class="k">this</span><span class="p">.</span><span class="nx">ref_count</span><span class="o">++</span><span class="p">;</span>
+ <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
+ <span class="p">};</span>
+ <span class="nx">RefCountable</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">release</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
+ <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">ref_count</span> <span class="o">&lt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="s2">&quot;LC.RefCounting: ref_count is corrupt: &quot;</span> <span class="o">+</span> <span class="k">this</span><span class="p">.</span><span class="nx">ref_count</span><span class="p">);</span>
+ <span class="p">}</span>
+ <span class="k">this</span><span class="p">.</span><span class="nx">ref_count</span><span class="o">--</span><span class="p">;</span>
+ <span class="k">if</span> <span class="p">((</span><span class="k">this</span><span class="p">.</span><span class="nx">ref_count</span> <span class="o">===</span> <span class="mi">0</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="k">this</span><span class="p">.</span><span class="nx">_destroy</span><span class="p">)</span> <span class="p">{</span>
+ <span class="k">this</span><span class="p">.</span><span class="nx">_destroy</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
+ <span class="p">}</span>
+ <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
+ <span class="p">};</span>
+ <span class="nx">RefCountable</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">refCount</span> <span class="o">=</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
+ <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="nx">ref_count</span><span class="p">;</span>
+ <span class="p">};</span>
+ <span class="k">return</span> <span class="nx">RefCountable</span><span class="p">;</span>
+<span class="p">})();</span>
+
+<span class="p">})();</span>
+
+</pre></div> </td> </tr> </tbody> </table> </div> </body> </html>
9 lifecycle-min.js
@@ -0,0 +1,9 @@
+// Lifecycle.js 1.0.0
+// (c) 2011 Kevin Malakoff.
+// Lifecycle is freely distributable under the MIT license.
+// https://github.com/kmalakoff/Lifecycle
+//
+(function(){this.Lifecyle||(this.Lifecyle={});this.LC=this.Lifecyle;LC.VERSION="1.0.0";LC.own=function(a,c){if(!a||typeof a!="object")return a;c||(c={});if(a.constructor==Array){var b,d=a.length;if(c.share_collection)for(b=0;b<d;b++)LC.own(a[b],{prefer_clone:c.prefer_clone});else{var e=[];for(b=0;b<d;b++)e.push(LC.own(a[b],{prefer_clone:c.prefer_clone}));return e}}else if(c.properties)if(c.share_collection)for(key in a)LC.own(a[key],{prefer_clone:c.prefer_clone});else{b={};for(key in a)b[key]=LC.own(a[key],
+{prefer_clone:c.prefer_clone});return b}else if(a.retain)if(c.prefer_clone&&a.clone)return a.clone();else a.retain();else if(a.clone)return a.clone();return a};LC.disown=function(a,c){if(!a||typeof a!="object")return a;c||(c={});if(a.constructor==Array){var b,d=a.length;if(c.clear_values)for(b=0;b<d;b++)LC.disown(a[b],{clear_values:c.clear_values}),a[b]=null;else{for(b=0;b<d;b++)LC.disown(a[b],{remove_values:c.remove_values});if(c.remove_values)a.length=0}}else if(c.properties)if(c.clear_values)for(b in a)LC.disown(a[b],
+{clear_values:c.clear_values}),a[b]=null;else{for(b in a)LC.disown(a[b],{remove_values:c.remove_values});if(c.remove_values)for(b in a)delete a[b]}else a.release?a.release():a.destroy&&a.destroy();return a};LC.RefCountable=function(){function a(){this.ref_count=1}a.prototype.retain=function(){if(this.ref_count<=0)throw Error("LC.RefCounting: ref_count is corrupt: "+this.ref_count);this.ref_count++;return this};a.prototype.release=function(){if(this.ref_count<=0)throw Error("LC.RefCounting: ref_count is corrupt: "+
+this.ref_count);this.ref_count--;this.ref_count===0&&this._destroy&&this._destroy.call(this);return this};a.prototype.refCount=function(){return this.ref_count};return a}()})();
112 lifecycle.js
@@ -0,0 +1,112 @@
+// Lifecycle.js 1.0.0
+// (c) 2011 Kevin Malakoff.
+// Lifecycle is freely distributable under the MIT license.
+// https://github.com/kmalakoff/Lifecycle
+//
+
+(function() {
+
+this.Lifecyle || (this.Lifecyle = {});
+this.LC = this.Lifecyle;
+LC.VERSION = '1.0.0';
+
+////////////////HELPERS - BEGIN//////////////////
+var isArray = function(obj) {
+ return obj.constructor == Array;
+};
+////////////////HELPERS - END//////////////////
+
+// Deduces the type of ownership of an item and if available, it retains it (reference counted) or clones it.
+// <br/>**Options:**<br/>
+// * `properties` - used to disambigate between owning an object and owning each property.<br/>
+// * `share_collection` - used to disambigate between owning a collection's items (share) and cloning a collection (don't share).
+// * `prefer_clone` - used to disambigate when both retain and clone exist. By default retain is prefered (eg. sharing for lower memory footprint).
+LC.own = function(obj, options) {
+ if (!obj || (typeof(obj)!='object')) return obj;
+ options || (options = {});
+ if (isArray(obj)) {
+ var i, l = obj.length;
+ if (options.share_collection) { for (i=0;i<l;i++) { LC.own(obj[i], {prefer_clone: options.prefer_clone}); } return obj; }
+ else {
+ var a_clone = [];
+ for (i=0;i<l;i++) { a_clone.push(LC.own(obj[i], {prefer_clone: options.prefer_clone})); }
+ return a_clone;
+ }
+ }
+ else if (options.properties) {
+ if (options.share_collection) { for (key in obj) { LC.own(obj[key], {prefer_clone: options.prefer_clone}); } return obj; }
+ else {
+ var b_clone = {};
+ for (key in obj) { b_clone[key] = LC.own(obj[key], {prefer_clone: options.prefer_clone}); }
+ return b_clone;
+ }
+ }
+ else if (obj.retain) {
+ if (options.prefer_clone && obj.clone) return obj.clone();
+ else obj.retain();
+ }
+ else if (obj.clone) return obj.clone();
+ return obj;
+};
+
+// Deduces the type of ownership of an item and if available, it releases it (reference counted) or destroys it.
+// <br/>**Options:**<br/>
+// * `properties` - used to disambigate between owning an object and owning each property.<br/>
+// * `clear_values` - used to disambigate between clearing disowned items and removing them (by default, they are removed).
+// * `remove_values` - used to indicate that the values should be disowned and removed from the collections.
+LC.disown = function(obj, options) {
+ if (!obj || (typeof(obj)!='object')) return obj;
+ options || (options = {});
+ if (isArray(obj)) {
+ var i, l = obj.length;
+ if (options.clear_values) { for (i=0;i<l;i++) { LC.disown(obj[i], {clear_values: options.clear_values}); obj[i]=null; } }
+ else {
+ for (i=0;i<l;i++) { LC.disown(obj[i], {remove_values: options.remove_values}); }
+ if (options.remove_values) {obj.length=0;}
+ }
+ return obj;
+ }
+ else if (options.properties) {
+ var key;
+ if (options.clear_values) { for (key in obj) { LC.disown(obj[key], {clear_values: options.clear_values}); obj[key]=null; } }
+ else {
+ for (key in obj) { LC.disown(obj[key], {remove_values: options.remove_values});}
+ if (options.remove_values) {for(key in obj) { delete obj[key]; }}
+ }
+ return obj;
+ }
+ else if (obj.release) obj.release();
+ else if (obj.destroy) obj.destroy();
+ return obj;
+};
+
+// A simple reference counting class using Coffeescript class construction.
+// Convention: implement a _destroy method with custom cleanup when reference count hits zero.
+LC.RefCountable = (function() {
+ function RefCountable() {
+ this.ref_count = 1;
+ }
+ RefCountable.prototype.retain = function() {
+ if (this.ref_count <= 0) {
+ throw new Error("LC.RefCounting: ref_count is corrupt: " + this.ref_count);
+ }
+ this.ref_count++;
+ return this;
+ };
+ RefCountable.prototype.release = function() {
+ if (this.ref_count <= 0) {
+ throw new Error("LC.RefCounting: ref_count is corrupt: " + this.ref_count);
+ }
+ this.ref_count--;
+ if ((this.ref_count === 0) && this._destroy) {
+ this._destroy.call(this);
+ }
+ return this;
+ };
+ RefCountable.prototype.refCount = function() {
+ return this.ref_count;
+ };
+ return RefCountable;
+})();
+
+})();
12 package.json
@@ -0,0 +1,12 @@
+{
+ "name" : "lifecycle",
+ "description" : "Lifecycle.js provides conventions and helpers to manage the life cycles of Javascript instances",
+ "homepage" : "https://github.com/kmalakoff/lifecycle",
+ "keywords" : ["util", "functional", "server", "client", "browser"],
+ "author" : "Kevin Malakoff <xmann.intl@gmail.com>",
+ "contributors" : [],
+ "dependencies" : [],
+ "repository" : {"type": "git", "url": "git://github.com/kmalakoff/lifecycle.git"},
+ "main" : "lifecycle.js",
+ "version" : "1.0.0"
+}
30 test/test.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Lifecycle Test Suite</title>
+ <link rel="stylesheet" href="vendor/qunit/qunit.css" type="text/css" media="screen" />
+ <script type="text/javascript" src="vendor/qunit/jquery.js"></script>
+ <script type="text/javascript" src="vendor/qunit/qunit.js"></script>
+ <script type="text/javascript" src="vendor/qunit/jslitmus.js"></script>
+
+ <script type="text/javascript" src="../lifecycle.js"></script>
+
+ <script type="text/javascript" src="test.js"></script>
+
+</head>
+<body>
+ <div class="lifecycle-test">
+ <h1 id="qunit-header">Lifecycle Test Suite</h1>
+ <h2 id="qunit-banner"></h2>
+ <h2 id="qunit-userAgent"></h2>
+ <ol id="qunit-tests"></ol>
+ <br />
+
+ <script type="text/html" id="template">
+ <%
+ if (data) { data += 12345; }; %>
+ <li><%= data %></li>
+ </script>
+ </div>
+</body>
+</html>
237 test/test.js
@@ -0,0 +1,237 @@
+var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) {
+ for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; }
+ function ctor() { this.constructor = child; }
+ ctor.prototype = parent.prototype;
+ child.prototype = new ctor;
+ child.__super__ = parent.prototype;
+ return child;
+}, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
+
+var size = function(obj) {
+ var size = 0;
+ for(var key in obj) {size++;}
+ return size;
+}
+
+var isArray = function(obj) {
+ return obj.constructor == Array;
+};
+
+var clone = function(obj) {
+ if (isArray(obj)) {
+ var clone = [];
+ for(var key in obj) {clone.push(obj[key]);}
+ return clone;
+ }
+ else {
+ var clone = {};
+ for(var key in obj) {if (obj.hasOwnProperty(key)) clone[key]=obj[key];}
+ return clone;
+ }
+}
+
+var root = this;
+
+$(document).ready(function() {
+ module("Lifecycle.js");
+
+ test('collections: own and disown', function() {
+ var original, original_again, copy;
+
+ original = null;
+ copy = LC.own(original);
+ ok(!copy, 'no instance');
+ LC.disown(original); LC.disown(copy);
+
+ CloneDestroy = (function() {
+ CloneDestroy.instance_count = 0;
+ function CloneDestroy() { CloneDestroy.instance_count++; }
+ CloneDestroy.prototype.clone = function() { return new CloneDestroy() };
+ CloneDestroy.prototype.destroy = function() { CloneDestroy.instance_count--; };
+ return CloneDestroy;
+ })();
+
+ CloneDestroy.instance_count = 0; original = new CloneDestroy();
+ equal(CloneDestroy.instance_count, 1, 'cd: 1 instance');
+ copy = LC.own(original);
+ equal(CloneDestroy.instance_count, 2, 'cd: 2 instances');
+ LC.disown(original);
+ equal(CloneDestroy.instance_count, 1, 'cd: 1 instance');
+ LC.disown(copy);
+ equal(CloneDestroy.instance_count, 0, 'cd: 0 instances');
+
+ CloneDestroy.instance_count = 0; original = [new CloneDestroy(), new CloneDestroy(), new CloneDestroy()];
+ equal(CloneDestroy.instance_count, 3, 'cd: 3 instances');
+ original_again = LC.own(original, {share_collection:true});
+ ok(original_again===original, 'cd: retained existing');
+ equal(CloneDestroy.instance_count, 6, 'cd: 6 instances');
+ copy = clone(original_again)
+ LC.disown(original); LC.disown(copy);
+ equal(CloneDestroy.instance_count, 0, 'cd: 0 instances');
+
+ CloneDestroy.instance_count = 0; original = [new CloneDestroy(), new CloneDestroy(), new CloneDestroy()];
+ equal(CloneDestroy.instance_count, 3, 'cd: 3 instances');
+ copy = LC.own(original);
+ ok(copy!==original, 'cd: retained existing');
+ equal(CloneDestroy.instance_count, 6, 'cd: 6 instances');
+ LC.disown(original); LC.disown(copy);
+ equal(CloneDestroy.instance_count, 0, 'cd: 0 instances');
+
+ CloneDestroy.instance_count = 0; original = {one:new CloneDestroy(), two:new CloneDestroy(), three:new CloneDestroy()};
+ equal(CloneDestroy.instance_count, 3, 'cd: 3 instances');
+ copy = LC.own(original, {properties:true});
+ equal(CloneDestroy.instance_count, 6, 'cd: 6 instances');
+ LC.disown(original, {properties:true}); LC.disown(copy, {properties:true});
+ equal(CloneDestroy.instance_count, 0, 'cd: 0 instances');
+
+ CloneDestroy.instance_count = 0; original = [new CloneDestroy(), new CloneDestroy(), new CloneDestroy()];
+ LC.disown(original, {clear_values:true});
+ equal(original.length, 3, 'cd: 3 instances');
+
+ RetainRelease = (function() {
+ RetainRelease.instance_count = 0;
+ function RetainRelease() { this.retain_count=1; RetainRelease.instance_count++ }
+ RetainRelease.prototype.retain = function() { this.retain_count++; };
+ RetainRelease.prototype.release = function() { this.retain_count--; if (this.retain_count==0) RetainRelease.instance_count--; };
+ return RetainRelease;
+ })();
+
+ RetainRelease.instance_count = 0; original = new RetainRelease();
+ equal(RetainRelease.instance_count, 1, 'rr: 1 instance');
+ equal(original.retain_count, 1, 'rr: 1 retain');
+ original_retained = LC.own(original);
+ equal(RetainRelease.instance_count, 1, 'rr: 1 instances');
+ ok(original_retained==original, 'rr: same object');
+ equal(original.retain_count, 2, 'rr: 2 retains');
+ LC.disown(original); LC.disown(original_retained);
+ equal(RetainRelease.instance_count, 0, 'rr: 0 instances');
+ equal(original.retain_count, 0, 'rr: 0 retains');
+
+ RetainRelease.instance_count = 0; original = [new RetainRelease(), new RetainRelease(), new RetainRelease()];
+ equal(RetainRelease.instance_count, 3, 'rr: 3 instances');
+ equal(original[0].retain_count, 1, 'rr: 1 retain');
+ original_retained = LC.own(original);
+ ok(original_retained!==original, 'rr: different object');
+ equal(RetainRelease.instance_count, 3, 'rr: 3 instances');
+ equal(original[0].retain_count, 2, 'rr: 2 retains');
+ LC.disown(original, {clear_values:false, remove_values:true});
+ equal(original.length, 0, 'rr: 0 values');
+ equal(RetainRelease.instance_count, 3, 'rr: 3 instances');
+ equal(original_retained[0].retain_count, 1, 'rr: 1 retain');
+ LC.disown(original_retained);
+ equal(RetainRelease.instance_count, 0, 'rr: 0 instances');
+
+ RetainRelease.instance_count = 0; original = [new RetainRelease(), new RetainRelease(), new RetainRelease()];
+ LC.disown(original, {clear_values:true});
+ equal(original.length, 3, 'rr: 3 values');
+
+ RetainRelease.instance_count = 0; original = {one:new RetainRelease(), two:new RetainRelease(), three:new RetainRelease()};
+ equal(RetainRelease.instance_count, 3, 'rr: 3 instances');
+ equal(original.one.retain_count, 1, 'rr: 1 retain');
+ original_again = LC.own(original, {share_collection:true, properties:true});
+ ok(original_again===original, 'rr: different object');
+ equal(RetainRelease.instance_count, 3, 'rr: 3 instances');
+ copy = clone(original_again);
+ LC.disown(original, {properties:true, clear_values:false, remove_values:true})
+ equal(size(original), 0, 'rr: 0 key/values');
+ equal(RetainRelease.instance_count, 3, 'rr: 3 instances');
+ LC.disown(copy, {properties:true});
+ equal(RetainRelease.instance_count, 0, 'rr: 0 instances');
+
+ RetainRelease.instance_count = 0; original = {one:new RetainRelease(), two:new RetainRelease(), three:new RetainRelease()};
+ equal(RetainRelease.instance_count, 3, 'rr: 3 instances');
+ equal(original.one.retain_count, 1, 'rr: 1 retain');
+ original_retained = LC.own(original, {share_collection:false, properties:true});
+ ok(original_retained!==original, 'rr: same object');
+ equal(RetainRelease.instance_count, 3, 'rr: 3 instances');
+ LC.disown(original, {properties:true, clear_values:true})
+ equal(size(original), 3, 'rr: 3 key/values');
+ equal(RetainRelease.instance_count, 3, 'rr: 3 instances');
+ equal(original_retained.one.retain_count, 1, 'rr: 1 retain');
+ LC.disown(original_retained, {properties:true});
+ equal(RetainRelease.instance_count, 0, 'rr: 0 instances');
+
+ RetainRelease.instance_count = 0; original = {one:new RetainRelease(), two:new RetainRelease(), three:new RetainRelease()};
+ LC.disown(original, {properties:true, clear_values:true});
+ equal(size(original), 3, 'rr: 3 instances');
+
+ RetainReleaseWithClone = (function() {
+ RetainReleaseWithClone.instance_count = 0;
+ function RetainReleaseWithClone() { this.retain_count=1; RetainReleaseWithClone.instance_count++; }
+ RetainReleaseWithClone.prototype.clone = function() { return new RetainReleaseWithClone(); };
+ RetainReleaseWithClone.prototype.retain = function() { this.retain_count++; };
+ RetainReleaseWithClone.prototype.release = function() { this.retain_count--; if (this.retain_count==0) RetainReleaseWithClone.instance_count--; };
+ return RetainReleaseWithClone;
+ })();
+
+ RetainReleaseWithClone.instance_count = 0; original = new RetainReleaseWithClone();
+ equal(RetainReleaseWithClone.instance_count, 1, 'rr: 1 instance');
+ equal(original.retain_count, 1, 'rrc: 1 retain');
+ copy = LC.own(original, {prefer_clone:true}); // a clone exists in addition to retain so use it instead of retain
+ equal(RetainReleaseWithClone.instance_count, 2, 'rrc: 2 instances');
+ ok(copy!=original, 'rrc: diferent objects');
+ ok(original.retain_count, 1, 'rrc: 1 retains');
+ equal(copy.retain_count, 1, 'rrc: 1 retains');
+ LC.disown(original); LC.disown(copy);
+ equal(RetainReleaseWithClone.instance_count, 0, 'rrc: 0 instances');
+ equal(original.retain_count, 0, 'rrc: 0 retains');
+ equal(copy.retain_count, 0, 'rrc: 0 retains');
+
+ // prefering retain is default, expect same result as RetainRelease
+ RetainReleaseWithClone.instance_count = 0; original = new RetainReleaseWithClone();
+ equal(RetainReleaseWithClone.instance_count, 1, 'rrc: 1 instance');
+ equal(original.retain_count, 1, 'rrc: 1 retain');
+ original_retained = LC.own(original);
+ equal(RetainReleaseWithClone.instance_count, 1, 'rrc: 1 instances');
+ ok(original_retained==original, 'rrc: same object');
+ equal(original.retain_count, 2, 'rrc: 2 retains');
+ LC.disown(original); LC.disown(original_retained);
+ equal(RetainReleaseWithClone.instance_count, 0, 'rrc: 0 instances');
+ equal(original.retain_count, 0, 'rrc: 0 retains');
+ });
+
+ test('collections: own and disown', function() {
+
+ MyClass = (function() {
+ __extends(MyClass, LC.RefCountable);
+ function MyClass() {
+ MyClass.__super__.constructor.apply(this, arguments);
+ this.is_alive = true;
+ }
+ MyClass.prototype._destroy = function() {
+ this.is_alive = false;
+ };
+ return MyClass;
+ })();
+
+ var instance = new MyClass();
+ equal(instance.is_alive, true, 'is alive');
+
+ equal(instance.refCount(), 1, '1 reference');
+ equal(instance.retain(), instance, 'chaining');
+ equal(instance.refCount(), 2, '2 references');
+ equal(instance.retain(), instance, 'chaining');
+ equal(instance.refCount(), 3, '3 references');
+ equal(instance.is_alive, true, 'is alive');
+
+ equal(instance.release(), instance, 'chaining');
+ equal(instance.refCount(), 2, '2 references');
+ equal(instance.is_alive, true, 'is alive');
+ equal(instance.retain(), instance, 'chaining');
+ equal(instance.refCount(), 3, '3 references');
+ equal(instance.is_alive, true, 'is alive');
+
+ equal(instance.release(), instance, 'chaining');
+ equal(instance.refCount(), 2, '2 references');
+ equal(instance.release(), instance, 'chaining');
+ equal(instance.refCount(), 1, '1 reference');
+ equal(instance.is_alive, true, 'is alive');
+
+ equal(instance.release(), instance, 'chaining');
+ equal(instance.refCount(), 0, '0 references');
+ equal(instance.is_alive, false, 'is gone');
+
+ raises(function(){instance.release()}, Error, 'LC.RefCounting: ref_count is corrupt');
+ equal(instance.is_alive, false, 'is gone');
+ });
+});
19 test/vendor/qunit/jquery.js
@@ -0,0 +1,19 @@
+/*
+ * jQuery JavaScript Library v1.3.2
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
+ * Revision: 6246
+ */
+(function(){var l=this,g,y=l.jQuery,p=l.$,o=l.jQuery=l.$=function(E,F){return new o.fn.init(E,F)},D=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;o.fn=o.prototype={init:function(E,H){E=E||document;if(E.nodeType){this[0]=E;this.length=1;this.context=E;return this}if(typeof E==="string"){var G=D.exec(E);if(G&&(G[1]||!H)){if(G[1]){E=o.clean([G[1]],H)}else{var I=document.getElementById(G[3]);if(I&&I.id!=G[3]){return o().find(E)}var F=o(I||[]);F.context=document;F.selector=E;return F}}else{return o(H).find(E)}}else{if(o.isFunction(E)){return o(document).ready(E)}}if(E.selector&&E.context){this.selector=E.selector;this.context=E.context}return this.setArray(o.isArray(E)?E:o.makeArray(E))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(E){return E===g?Array.prototype.slice.call(this):this[E]},pushStack:function(F,H,E){var G=o(F);G.prevObject=this;G.context=this.context;if(H==="find"){G.selector=this.selector+(this.selector?" ":"")+E}else{if(H){G.selector=this.selector+"."+H+"("+E+")"}}return G},setArray:function(E){this.length=0;Array.prototype.push.apply(this,E);return this},each:function(F,E){return o.each(this,F,E)},index:function(E){return o.inArray(E&&E.jquery?E[0]:E,this)},attr:function(F,H,G){var E=F;if(typeof F==="string"){if(H===g){return this[0]&&o[G||"attr"](this[0],F)}else{E={};E[F]=H}}return this.each(function(I){for(F in E){o.attr(G?this.style:this,F,o.prop(this,E[F],G,I,F))}})},css:function(E,F){if((E=="width"||E=="height")&&parseFloat(F)<0){F=g}return this.attr(E,F,"curCSS")},text:function(F){if(typeof F!=="object"&&F!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(F))}var E="";o.each(F||this,function(){o.each(this.childNodes,function(){if(this.nodeType!=8){E+=this.nodeType!=1?this.nodeValue:o.fn.text([this])}})});return E},wrapAll:function(E){if(this[0]){var F=o(E,this[0].ownerDocument).clone();if(this[0].parentNode){F.insertBefore(this[0])}F.map(function(){var G=this;while(G.firstChild){G=G.firstChild}return G}).append(this)}return this},wrapInner:function(E){return this.each(function(){o(this).contents().wrapAll(E)})},wrap:function(E){return this.each(function(){o(this).wrapAll(E)})},append:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.appendChild(E)}})},prepend:function(){return this.domManip(arguments,true,function(E){if(this.nodeType==1){this.insertBefore(E,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this)})},after:function(){return this.domManip(arguments,false,function(E){this.parentNode.insertBefore(E,this.nextSibling)})},end:function(){return this.prevObject||o([])},push:[].push,sort:[].sort,splice:[].splice,find:function(E){if(this.length===1){var F=this.pushStack([],"find",E);F.length=0;o.find(E,this[0],F);return F}else{return this.pushStack(o.unique(o.map(this,function(G){return o.find(E,G)})),"find",E)}},clone:function(G){var E=this.map(function(){if(!o.support.noCloneEvent&&!o.isXMLDoc(this)){var I=this.outerHTML;if(!I){var J=this.ownerDocument.createElement("div");J.appendChild(this.cloneNode(true));I=J.innerHTML}return o.clean([I.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(G===true){var H=this.find("*").andSelf(),F=0;E.find("*").andSelf().each(function(){if(this.nodeName!==H[F].nodeName){return}var I=o.data(H[F],"events");for(var K in I){for(var J in I[K]){o.event.add(this,K,I[K][J],I[K][J].data)}}F++})}return E},filter:function(E){return this.pushStack(o.isFunction(E)&&o.grep(this,function(G,F){return E.call(G,F)})||o.multiFilter(E,o.grep(this,function(F){return F.nodeType===1})),"filter",E)},closest:function(E){var G=o.expr.match.POS.test(E)?o(E):null,F=0;return this.map(function(){var H=this;while(H&&H.ownerDocument){if(G?G.index(H)>-1:o(H).is(E)){o.data(H,"closest",F);return H}H=H.parentNode;F++}})},not:function(E){if(typeof E==="string"){if(f.test(E)){return this.pushStack(o.multiFilter(E,this,true),"not",E)}else{E=o.multiFilter(E,this)}}var F=E.length&&E[E.length-1]!==g&&!E.nodeType;return this.filter(function(){return F?o.inArray(this,E)<0:this!=E})},add:function(E){return this.pushStack(o.unique(o.merge(this.get(),typeof E==="string"?o(E):o.makeArray(E))))},is:function(E){return !!E&&o.multiFilter(E,this).length>0},hasClass:function(E){return !!E&&this.is("."+E)},val:function(K){if(K===g){var E=this[0];if(E){if(o.nodeName(E,"option")){return(E.attributes.value||{}).specified?E.value:E.text}if(o.nodeName(E,"select")){var I=E.selectedIndex,L=[],M=E.options,H=E.type=="select-one";if(I<0){return null}for(var F=H?I:0,J=H?I+1:M.length;F<J;F++){var G=M[F];if(G.selected){K=o(G).val();if(H){return K}L.push(K)}}return L}return(E.value||"").replace(/\r/g,"")}return g}if(typeof K==="number"){K+=""}return this.each(function(){if(this.nodeType!=1){return}if(o.isArray(K)&&/radio|checkbox/.test(this.type)){this.checked=(o.inArray(this.value,K)>=0||o.inArray(this.name,K)>=0)}else{if(o.nodeName(this,"select")){var N=o.makeArray(K);o("option",this).each(function(){this.selected=(o.inArray(this.value,N)>=0||o.inArray(this.text,N)>=0)});if(!N.length){this.selectedIndex=-1}}else{this.value=K}}})},html:function(E){return E===g?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(E)},replaceWith:function(E){return this.after(E).remove()},eq:function(E){return this.slice(E,+E+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(E){return this.pushStack(o.map(this,function(G,F){return E.call(G,F,G)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=o.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild;if(H){for(var G=0,E=this.length;G<E;G++){L.call(K(this[G],H),this.length>1||G>0?I.cloneNode(true):I)}}if(F){o.each(F,z)}}return this;function K(N,O){return M&&o.nodeName(N,"table")&&o.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};o.fn.init.prototype=o.fn;function z(E,F){if(F.src){o.ajax({url:F.src,async:false,dataType:"script"})}else{o.globalEval(F.text||F.textContent||F.innerHTML||"")}if(F.parentNode){F.parentNode.removeChild(F)}}function e(){return +new Date}o.extend=o.fn.extend=function(){var J=arguments[0]||{},H=1,I=arguments.length,E=false,G;if(typeof J==="boolean"){E=J;J=arguments[1]||{};H=2}if(typeof J!=="object"&&!o.isFunction(J)){J={}}if(I==H){J=this;--H}for(;H<I;H++){if((G=arguments[H])!=null){for(var F in G){var K=J[F],L=G[F];if(J===L){continue}if(E&&L&&typeof L==="object"&&!L.nodeType){J[F]=o.extend(E,K||(L.length!=null?[]:{}),L)}else{if(L!==g){J[F]=L}}}}}return J};var b=/z-?index|font-?weight|opacity|zoom|line-?height/i,q=document.defaultView||{},s=Object.prototype.toString;o.extend({noConflict:function(E){l.$=p;if(E){l.jQuery=y}return o},isFunction:function(E){return s.call(E)==="[object Function]"},isArray:function(E){return s.call(E)==="[object Array]"},isXMLDoc:function(E){return E.nodeType===9&&E.documentElement.nodeName!=="HTML"||!!E.ownerDocument&&o.isXMLDoc(E.ownerDocument)},globalEval:function(G){if(G&&/\S/.test(G)){var F=document.getElementsByTagName("head")[0]||document.documentElement,E=document.createElement("script");E.type="text/javascript";if(o.support.scriptEval){E.appendChild(document.createTextNode(G))}else{E.text=G}F.insertBefore(E,F.firstChild);F.removeChild(E)}},nodeName:function(F,E){return F.nodeName&&F.nodeName.toUpperCase()==E.toUpperCase()},each:function(G,K,F){var E,H=0,I=G.length;if(F){if(I===g){for(E in G){if(K.apply(G[E],F)===false){break}}}else{for(;H<I;){if(K.apply(G[H++],F)===false){break}}}}else{if(I===g){for(E in G){if(K.call(G[E],E,G[E])===false){break}}}else{for(var J=G[0];H<I&&K.call(J,H,J)!==false;J=G[++H]){}}}return G},prop:function(H,I,G,F,E){if(o.isFunction(I)){I=I.call(H,F)}return typeof I==="number"&&G=="curCSS"&&!b.test(E)?I+"px":I},className:{add:function(E,F){o.each((F||"").split(/\s+/),function(G,H){if(E.nodeType==1&&!o.className.has(E.className,H)){E.className+=(E.className?" ":"")+H}})},remove:function(E,F){if(E.nodeType==1){E.className=F!==g?o.grep(E.className.split(/\s+/),function(G){return !o.className.has(F,G)}).join(" "):""}},has:function(F,E){return F&&o.inArray(E,(F.className||F).toString().split(/\s+/))>-1}},swap:function(H,G,I){var E={};for(var F in G){E[F]=H.style[F];H.style[F]=G[F]}I.call(H);for(var F in G){H.style[F]=E[F]}},css:function(H,F,J,E){if(F=="width"||F=="height"){var L,G={position:"absolute",visibility:"hidden",display:"block"},K=F=="width"?["Left","Right"]:["Top","Bottom"];function I(){L=F=="width"?H.offsetWidth:H.offsetHeight;if(E==="border"){return}o.each(K,function(){if(!E){L-=parseFloat(o.curCSS(H,"padding"+this,true))||0}if(E==="margin"){L+=parseFloat(o.curCSS(H,"margin"+this,true))||0}else{L-=parseFloat(o.curCSS(H,"border"+this+"Width",true))||0}})}if(H.offsetWidth!==0){I()}else{o.swap(H,G,I)}return Math.max(0,Math.round(L))}return o.curCSS(H,F,J)},curCSS:function(I,F,G){var L,E=I.style;if(F=="opacity"&&!o.support.opacity){L=o.attr(E,"opacity");return L==""?"1":L}if(F.match(/float/i)){F=w}if(!G&&E&&E[F]){L=E[F]}else{if(q.getComputedStyle){if(F.match(/float/i)){F="float"}F=F.replace(/([A-Z])/g,"-$1").toLowerCase();var M=q.getComputedStyle(I,null);if(M){L=M.getPropertyValue(F)}if(F=="opacity"&&L==""){L="1"}}else{if(I.currentStyle){var J=F.replace(/\-(\w)/g,function(N,O){return O.toUpperCase()});L=I.currentStyle[F]||I.currentStyle[J];if(!/^\d+(px)?$/i.test(L)&&/^\d/.test(L)){var H=E.left,K=I.runtimeStyle.left;I.runtimeStyle.left=I.currentStyle.left;E.left=L||0;L=E.pixelLeft+"px";E.left=H;I.runtimeStyle.left=K}}}}return L},clean:function(F,K,I){K=K||document;if(typeof K.createElement==="undefined"){K=K.ownerDocument||K[0]&&K[0].ownerDocument||document}if(!I&&F.length===1&&typeof F[0]==="string"){var H=/^<(\w+)\s*\/?>$/.exec(F[0]);if(H){return[K.createElement(H[1])]}}var G=[],E=[],L=K.createElement("div");o.each(F,function(P,S){if(typeof S==="number"){S+=""}if(!S){return}if(typeof S==="string"){S=S.replace(/(<(\w+)[^>]*?)\/>/g,function(U,V,T){return T.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?U:V+"></"+T+">"});var O=S.replace(/^\s+/,"").substring(0,10).toLowerCase();var Q=!O.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!O.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!O.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!O.indexOf("<td")||!O.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!O.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!o.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/<tbody/i.test(S),N=!O.indexOf("<table")&&!R?L.firstChild&&L.firstChild.childNodes:Q[1]=="<table>"&&!R?L.childNodes:[];for(var M=N.length-1;M>=0;--M){if(o.nodeName(N[M],"tbody")&&!N[M].childNodes.length){N[M].parentNode.removeChild(N[M])}}}if(!o.support.leadingWhitespace&&/^\s/.test(S)){L.insertBefore(K.createTextNode(S.match(/^\s*/)[0]),L.firstChild)}S=o.makeArray(L.childNodes)}if(S.nodeType){G.push(S)}else{G=o.merge(G,S)}});if(I){for(var J=0;G[J];J++){if(o.nodeName(G[J],"script")&&(!G[J].type||G[J].type.toLowerCase()==="text/javascript")){E.push(G[J].parentNode?G[J].parentNode.removeChild(G[J]):G[J])}else{if(G[J].nodeType===1){G.splice.apply(G,[J+1,0].concat(o.makeArray(G[J].getElementsByTagName("script"))))}I.appendChild(G[J])}}return E}return G},attr:function(J,G,K){if(!J||J.nodeType==3||J.nodeType==8){return g}var H=!o.isXMLDoc(J),L=K!==g;G=H&&o.props[G]||G;if(J.tagName){var F=/href|src|style/.test(G);if(G=="selected"&&J.parentNode){J.parentNode.selectedIndex}if(G in J&&H&&!F){if(L){if(G=="type"&&o.nodeName(J,"input")&&J.parentNode){throw"type property can't be changed"}J[G]=K}if(o.nodeName(J,"form")&&J.getAttributeNode(G)){return J.getAttributeNode(G).nodeValue}if(G=="tabIndex"){var I=J.getAttributeNode("tabIndex");return I&&I.specified?I.value:J.nodeName.match(/(button|input|object|select|textarea)/i)?0:J.nodeName.match(/^(a|area)$/i)&&J.href?0:g}return J[G]}if(!o.support.style&&H&&G=="style"){return o.attr(J.style,"cssText",K)}if(L){J.setAttribute(G,""+K)}var E=!o.support.hrefNormalized&&H&&F?J.getAttribute(G,2):J.getAttribute(G);return E===null?g:E}if(!o.support.opacity&&G=="opacity"){if(L){J.zoom=1;J.filter=(J.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(K)+""=="NaN"?"":"alpha(opacity="+K*100+")")}return J.filter&&J.filter.indexOf("opacity=")>=0?(parseFloat(J.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}G=G.replace(/-([a-z])/ig,function(M,N){return N.toUpperCase()});if(L){J[G]=K}return J[G]},trim:function(E){return(E||"").replace(/^\s+|\s+$/g,"")},makeArray:function(G){var E=[];if(G!=null){var F=G.length;if(F==null||typeof G==="string"||o.isFunction(G)||G.setInterval){E[0]=G}else{while(F){E[--F]=G[F]}}}return E},inArray:function(G,H){for(var E=0,F=H.length;E<F;E++){if(H[E]===G){return E}}return -1},merge:function(H,E){var F=0,G,I=H.length;if(!o.support.getAll){while((G=E[F++])!=null){if(G.nodeType!=8){H[I++]=G}}}else{while((G=E[F++])!=null){H[I++]=G}}return H},unique:function(K){var F=[],E={};try{for(var G=0,H=K.length;G<H;G++){var J=o.data(K[G]);if(!E[J]){E[J]=true;F.push(K[G])}}}catch(I){F=K}return F},grep:function(F,J,E){var G=[];for(var H=0,I=F.length;H<I;H++){if(!E!=!J(F[H],H)){G.push(F[H])}}return G},map:function(E,J){var F=[];for(var G=0,H=E.length;G<H;G++){var I=J(E[G],G);if(I!=null){F[F.length]=I}}return F.concat.apply([],F)}});var C=navigator.userAgent.toLowerCase();o.browser={version:(C.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(C),opera:/opera/.test(C),msie:/msie/.test(C)&&!/opera/.test(C),mozilla:/mozilla/.test(C)&&!/(compatible|webkit)/.test(C)};o.each({parent:function(E){return E.parentNode},parents:function(E){return o.dir(E,"parentNode")},next:function(E){return o.nth(E,2,"nextSibling")},prev:function(E){return o.nth(E,2,"previousSibling")},nextAll:function(E){return o.dir(E,"nextSibling")},prevAll:function(E){return o.dir(E,"previousSibling")},siblings:function(E){return o.sibling(E.parentNode.firstChild,E)},children:function(E){return o.sibling(E.firstChild)},contents:function(E){return o.nodeName(E,"iframe")?E.contentDocument||E.contentWindow.document:o.makeArray(E.childNodes)}},function(E,F){o.fn[E]=function(G){var H=o.map(this,F);if(G&&typeof G=="string"){H=o.multiFilter(G,H)}return this.pushStack(o.unique(H),E,G)}});o.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(E,F){o.fn[E]=function(G){var J=[],L=o(G);for(var K=0,H=L.length;K<H;K++){var I=(K>0?this.clone(true):this).get();o.fn[F].apply(o(L[K]),I);J=J.concat(I)}return this.pushStack(J,E,G)}});o.each({removeAttr:function(E){o.attr(this,E,"");if(this.nodeType==1){this.removeAttribute(E)}},addClass:function(E){o.className.add(this,E)},removeClass:function(E){o.className.remove(this,E)},toggleClass:function(F,E){if(typeof E!=="boolean"){E=!o.className.has(this,F)}o.className[E?"add":"remove"](this,F)},remove:function(E){if(!E||o.filter(E,[this]).length){o("*",this).add([this]).each(function(){o.event.remove(this);o.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){o(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(E,F){o.fn[E]=function(){return this.each(F,arguments)}});function j(E,F){return E[0]&&parseInt(o.curCSS(E[0],F,true),10)||0}var h="jQuery"+e(),v=0,A={};o.extend({cache:{},data:function(F,E,G){F=F==l?A:F;var H=F[h];if(!H){H=F[h]=++v}if(E&&!o.cache[H]){o.cache[H]={}}if(G!==g){o.cache[H][E]=G}return E?o.cache[H][E]:H},removeData:function(F,E){F=F==l?A:F;var H=F[h];if(E){if(o.cache[H]){delete o.cache[H][E];E="";for(E in o.cache[H]){break}if(!E){o.removeData(F)}}}else{try{delete F[h]}catch(G){if(F.removeAttribute){F.removeAttribute(h)}}delete o.cache[H]}},queue:function(F,E,H){if(F){E=(E||"fx")+"queue";var G=o.data(F,E);if(!G||o.isArray(H)){G=o.data(F,E,o.makeArray(H))}else{if(H){G.push(H)}}}return G},dequeue:function(H,G){var E=o.queue(H,G),F=E.shift();if(!G||G==="fx"){F=E[0]}if(F!==g){F.call(H)}}});o.fn.extend({data:function(E,G){var H=E.split(".");H[1]=H[1]?"."+H[1]:"";if(G===g){var F=this.triggerHandler("getData"+H[1]+"!",[H[0]]);if(F===g&&this.length){F=o.data(this[0],E)}return F===g&&H[1]?this.data(H[0]):F}else{return this.trigger("setData"+H[1]+"!",[H[0],G]).each(function(){o.data(this,E,G)})}},removeData:function(E){return this.each(function(){o.removeData(this,E)})},queue:function(E,F){if(typeof E!=="string"){F=E;E="fx"}if(F===g){return o.queue(this[0],E)}return this.each(function(){var G=o.queue(this,E,F);if(E=="fx"&&G.length==1){G[0].call(this)}})},dequeue:function(E){return this.each(function(){o.dequeue(this,E)})}});
+/*
+ * Sizzle CSS Selector Engine - v0.9.3
+ * Copyright 2009, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+(function(){var R=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,L=0,H=Object.prototype.toString;var F=function(Y,U,ab,ac){ab=ab||[];U=U||document;if(U.nodeType!==1&&U.nodeType!==9){return[]}if(!Y||typeof Y!=="string"){return ab}var Z=[],W,af,ai,T,ad,V,X=true;R.lastIndex=0;while((W=R.exec(Y))!==null){Z.push(W[1]);if(W[2]){V=RegExp.rightContext;break}}if(Z.length>1&&M.exec(Y)){if(Z.length===2&&I.relative[Z[0]]){af=J(Z[0]+Z[1],U)}else{af=I.relative[Z[0]]?[U]:F(Z.shift(),U);while(Z.length){Y=Z.shift();if(I.relative[Y]){Y+=Z.shift()}af=J(Y,af)}}}else{var ae=ac?{expr:Z.pop(),set:E(ac)}:F.find(Z.pop(),Z.length===1&&U.parentNode?U.parentNode:U,Q(U));af=F.filter(ae.expr,ae.set);if(Z.length>0){ai=E(af)}else{X=false}while(Z.length){var ah=Z.pop(),ag=ah;if(!I.relative[ah]){ah=""}else{ag=Z.pop()}if(ag==null){ag=U}I.relative[ah](ai,ag,Q(U))}}if(!ai){ai=af}if(!ai){throw"Syntax error, unrecognized expression: "+(ah||Y)}if(H.call(ai)==="[object Array]"){if(!X){ab.push.apply(ab,ai)}else{if(U.nodeType===1){for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&(ai[aa]===true||ai[aa].nodeType===1&&K(U,ai[aa]))){ab.push(af[aa])}}}else{for(var aa=0;ai[aa]!=null;aa++){if(ai[aa]&&ai[aa].nodeType===1){ab.push(af[aa])}}}}}else{E(ai,ab)}if(V){F(V,U,ab,ac);if(G){hasDuplicate=false;ab.sort(G);if(hasDuplicate){for(var aa=1;aa<ab.length;aa++){if(ab[aa]===ab[aa-1]){ab.splice(aa--,1)}}}}}return ab};F.matches=function(T,U){return F(T,null,null,U)};F.find=function(aa,T,ab){var Z,X;if(!aa){return[]}for(var W=0,V=I.order.length;W<V;W++){var Y=I.order[W],X;if((X=I.match[Y].exec(aa))){var U=RegExp.leftContext;if(U.substr(U.length-1)!=="\\"){X[1]=(X[1]||"").replace(/\\/g,"");Z=I.find[Y](X,T,ab);if(Z!=null){aa=aa.replace(I.match[Y],"");break}}}}if(!Z){Z=T.getElementsByTagName("*")}return{set:Z,expr:aa}};F.filter=function(ad,ac,ag,W){var V=ad,ai=[],aa=ac,Y,T,Z=ac&&ac[0]&&Q(ac[0]);while(ad&&ac.length){for(var ab in I.filter){if((Y=I.match[ab].exec(ad))!=null){var U=I.filter[ab],ah,af;T=false;if(aa==ai){ai=[]}if(I.preFilter[ab]){Y=I.preFilter[ab](Y,aa,ag,ai,W,Z);if(!Y){T=ah=true}else{if(Y===true){continue}}}if(Y){for(var X=0;(af=aa[X])!=null;X++){if(af){ah=U(af,Y,X,aa);var ae=W^!!ah;if(ag&&ah!=null){if(ae){T=true}else{aa[X]=false}}else{if(ae){ai.push(af);T=true}}}}}if(ah!==g){if(!ag){aa=ai}ad=ad.replace(I.match[ab],"");if(!T){return[]}break}}}if(ad==V){if(T==null){throw"Syntax error, unrecognized expression: "+ad}else{break}}V=ad}return aa};var I=F.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(T){return T.getAttribute("href")}},relative:{"+":function(aa,T,Z){var X=typeof T==="string",ab=X&&!/\W/.test(T),Y=X&&!ab;if(ab&&!Z){T=T.toUpperCase()}for(var W=0,V=aa.length,U;W<V;W++){if((U=aa[W])){while((U=U.previousSibling)&&U.nodeType!==1){}aa[W]=Y||U&&U.nodeName===T?U||false:U===T}}if(Y){F.filter(T,aa,true)}},">":function(Z,U,aa){var X=typeof U==="string";if(X&&!/\W/.test(U)){U=aa?U:U.toUpperCase();for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){var W=Y.parentNode;Z[V]=W.nodeName===U?W:false}}}else{for(var V=0,T=Z.length;V<T;V++){var Y=Z[V];if(Y){Z[V]=X?Y.parentNode:Y.parentNode===U}}if(X){F.filter(U,Z,true)}}},"":function(W,U,Y){var V=L++,T=S;if(!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("parentNode",U,V,W,X,Y)},"~":function(W,U,Y){var V=L++,T=S;if(typeof U==="string"&&!U.match(/\W/)){var X=U=Y?U:U.toUpperCase();T=P}T("previousSibling",U,V,W,X,Y)}},find:{ID:function(U,V,W){if(typeof V.getElementById!=="undefined"&&!W){var T=V.getElementById(U[1]);return T?[T]:[]}},NAME:function(V,Y,Z){if(typeof Y.getElementsByName!=="undefined"){var U=[],X=Y.getElementsByName(V[1]);for(var W=0,T=X.length;W<T;W++){if(X[W].getAttribute("name")===V[1]){U.push(X[W])}}return U.length===0?null:U}},TAG:function(T,U){return U.getElementsByTagName(T[1])}},preFilter:{CLASS:function(W,U,V,T,Z,aa){W=" "+W[1].replace(/\\/g,"")+" ";if(aa){return W}for(var X=0,Y;(Y=U[X])!=null;X++){if(Y){if(Z^(Y.className&&(" "+Y.className+" ").indexOf(W)>=0)){if(!V){T.push(Y)}}else{if(V){U[X]=false}}}}return false},ID:function(T){return T[1].replace(/\\/g,"")},TAG:function(U,T){for(var V=0;T[V]===false;V++){}return T[V]&&Q(T[V])?U[1]:U[1].toUpperCase()},CHILD:function(T){if(T[1]=="nth"){var U=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(T[2]=="even"&&"2n"||T[2]=="odd"&&"2n+1"||!/\D/.test(T[2])&&"0n+"+T[2]||T[2]);T[2]=(U[1]+(U[2]||1))-0;T[3]=U[3]-0}T[0]=L++;return T},ATTR:function(X,U,V,T,Y,Z){var W=X[1].replace(/\\/g,"");if(!Z&&I.attrMap[W]){X[1]=I.attrMap[W]}if(X[2]==="~="){X[4]=" "+X[4]+" "}return X},PSEUDO:function(X,U,V,T,Y){if(X[1]==="not"){if(X[3].match(R).length>1||/^\w/.test(X[3])){X[3]=F(X[3],null,null,U)}else{var W=F.filter(X[3],U,V,true^Y);if(!V){T.push.apply(T,W)}return false}}else{if(I.match.POS.test(X[0])||I.match.CHILD.test(X[0])){return true}}return X},POS:function(T){T.unshift(true);return T}},filters:{enabled:function(T){return T.disabled===false&&T.type!=="hidden"},disabled:function(T){return T.disabled===true},checked:function(T){return T.checked===true},selected:function(T){T.parentNode.selectedIndex;return T.selected===true},parent:function(T){return !!T.firstChild},empty:function(T){return !T.firstChild},has:function(V,U,T){return !!F(T[3],V).length},header:function(T){return/h\d/i.test(T.nodeName)},text:function(T){return"text"===T.type},radio:function(T){return"radio"===T.type},checkbox:function(T){return"checkbox"===T.type},file:function(T){return"file"===T.type},password:function(T){return"password"===T.type},submit:function(T){return"submit"===T.type},image:function(T){return"image"===T.type},reset:function(T){return"reset"===T.type},button:function(T){return"button"===T.type||T.nodeName.toUpperCase()==="BUTTON"},input:function(T){return/input|select|textarea|button/i.test(T.nodeName)}},setFilters:{first:function(U,T){return T===0},last:function(V,U,T,W){return U===W.length-1},even:function(U,T){return T%2===0},odd:function(U,T){return T%2===1},lt:function(V,U,T){return U<T[3]-0},gt:function(V,U,T){return U>T[3]-0},nth:function(V,U,T){return T[3]-0==U},eq:function(V,U,T){return T[3]-0==U}},filter:{PSEUDO:function(Z,V,W,aa){var U=V[1],X=I.filters[U];if(X){return X(Z,W,V,aa)}else{if(U==="contains"){return(Z.textContent||Z.innerText||"").indexOf(V[3])>=0}else{if(U==="not"){var Y=V[3];for(var W=0,T=Y.length;W<T;W++){if(Y[W]===Z){return false}}return true}}}},CHILD:function(T,W){var Z=W[1],U=T;switch(Z){case"only":case"first":while(U=U.previousSibling){if(U.nodeType===1){return false}}if(Z=="first"){return true}U=T;case"last":while(U=U.nextSibling){if(U.nodeType===1){return false}}return true;case"nth":var V=W[2],ac=W[3];if(V==1&&ac==0){return true}var Y=W[0],ab=T.parentNode;if(ab&&(ab.sizcache!==Y||!T.nodeIndex)){var X=0;for(U=ab.firstChild;U;U=U.nextSibling){if(U.nodeType===1){U.nodeIndex=++X}}ab.sizcache=Y}var aa=T.nodeIndex-ac;if(V==0){return aa==0}else{return(aa%V==0&&aa/V>=0)}}},ID:function(U,T){return U.nodeType===1&&U.getAttribute("id")===T},TAG:function(U,T){return(T==="*"&&U.nodeType===1)||U.nodeName===T},CLASS:function(U,T){return(" "+(U.className||U.getAttribute("class"))+" ").indexOf(T)>-1},ATTR:function(Y,W){var V=W[1],T=I.attrHandle[V]?I.attrHandle[V](Y):Y[V]!=null?Y[V]:Y.getAttribute(V),Z=T+"",X=W[2],U=W[4];return T==null?X==="!=":X==="="?Z===U:X==="*="?Z.indexOf(U)>=0:X==="~="?(" "+Z+" ").indexOf(U)>=0:!U?Z&&T!==false:X==="!="?Z!=U:X==="^="?Z.indexOf(U)===0:X==="$="?Z.substr(Z.length-U.length)===U:X==="|="?Z===U||Z.substr(0,U.length+1)===U+"-":false},POS:function(X,U,V,Y){var T=U[2],W=I.setFilters[T];if(W){return W(X,V,U,Y)}}}};var M=I.match.POS;for(var O in I.match){I.match[O]=RegExp(I.match[O].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var E=function(U,T){U=Array.prototype.slice.call(U);if(T){T.push.apply(T,U);return T}return U};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(N){E=function(X,W){var U=W||[];if(H.call(X)==="[object Array]"){Array.prototype.push.apply(U,X)}else{if(typeof X.length==="number"){for(var V=0,T=X.length;V<T;V++){U.push(X[V])}}else{for(var V=0;X[V];V++){U.push(X[V])}}}return U}}var G;if(document.documentElement.compareDocumentPosition){G=function(U,T){var V=U.compareDocumentPosition(T)&4?-1:U===T?0:1;if(V===0){hasDuplicate=true}return V}}else{if("sourceIndex" in document.documentElement){G=function(U,T){var V=U.sourceIndex-T.sourceIndex;if(V===0){hasDuplicate=true}return V}}else{if(document.createRange){G=function(W,U){var V=W.ownerDocument.createRange(),T=U.ownerDocument.createRange();V.selectNode(W);V.collapse(true);T.selectNode(U);T.collapse(true);var X=V.compareBoundaryPoints(Range.START_TO_END,T);if(X===0){hasDuplicate=true}return X}}}}(function(){var U=document.createElement("form"),V="script"+(new Date).getTime();U.innerHTML="<input name='"+V+"'/>";var T=document.documentElement;T.insertBefore(U,T.firstChild);if(!!document.getElementById(V)){I.find.ID=function(X,Y,Z){if(typeof Y.getElementById!=="undefined"&&!Z){var W=Y.getElementById(X[1]);return W?W.id===X[1]||typeof W.getAttributeNode!=="undefined"&&W.getAttributeNode("id").nodeValue===X[1]?[W]:g:[]}};I.filter.ID=function(Y,W){var X=typeof Y.getAttributeNode!=="undefined"&&Y.getAttributeNode("id");return Y.nodeType===1&&X&&X.nodeValue===W}}T.removeChild(U)})();(function(){var T=document.createElement("div");T.appendChild(document.createComment(""));if(T.getElementsByTagName("*").length>0){I.find.TAG=function(U,Y){var X=Y.getElementsByTagName(U[1]);if(U[1]==="*"){var W=[];for(var V=0;X[V];V++){if(X[V].nodeType===1){W.push(X[V])}}X=W}return X}}T.innerHTML="<a href='#'></a>";if(T.firstChild&&typeof T.firstChild.getAttribute!=="undefined"&&T.firstChild.getAttribute("href")!=="#"){I.attrHandle.href=function(U){return U.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var T=F,U=document.createElement("div");U.innerHTML="<p class='TEST'></p>";if(U.querySelectorAll&&U.querySelectorAll(".TEST").length===0){return}F=function(Y,X,V,W){X=X||document;if(!W&&X.nodeType===9&&!Q(X)){try{return E(X.querySelectorAll(Y),V)}catch(Z){}}return T(Y,X,V,W)};F.find=T.find;F.filter=T.filter;F.selectors=T.selectors;F.matches=T.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var T=document.createElement("div");T.innerHTML="<div class='test e'></div><div class='test'></div>";if(T.getElementsByClassName("e").length===0){return}T.lastChild.className="e";if(T.getElementsByClassName("e").length===1){return}I.order.splice(1,0,"CLASS");I.find.CLASS=function(U,V,W){if(typeof V.getElementsByClassName!=="undefined"&&!W){return V.getElementsByClassName(U[1])}}})()}function P(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1&&!ac){T.sizcache=Y;T.sizset=W}if(T.nodeName===Z){X=T;break}T=T[U]}ad[W]=X}}}function S(U,Z,Y,ad,aa,ac){var ab=U=="previousSibling"&&!ac;for(var W=0,V=ad.length;W<V;W++){var T=ad[W];if(T){if(ab&&T.nodeType===1){T.sizcache=Y;T.sizset=W}T=T[U];var X=false;while(T){if(T.sizcache===Y){X=ad[T.sizset];break}if(T.nodeType===1){if(!ac){T.sizcache=Y;T.sizset=W}if(typeof Z!=="string"){if(T===Z){X=true;break}}else{if(F.filter(Z,[T]).length>0){X=T;break}}}T=T[U]}ad[W]=X}}}var K=document.compareDocumentPosition?function(U,T){return U.compareDocumentPosition(T)&16}:function(U,T){return U!==T&&(U.contains?U.contains(T):true)};var Q=function(T){return T.nodeType===9&&T.documentElement.nodeName!=="HTML"||!!T.ownerDocument&&Q(T.ownerDocument)};var J=function(T,aa){var W=[],X="",Y,V=aa.nodeType?[aa]:aa;while((Y=I.match.PSEUDO.exec(T))){X+=Y[0];T=T.replace(I.match.PSEUDO,"")}T=I.relative[T]?T+"*":T;for(var Z=0,U=V.length;Z<U;Z++){F(T,V[Z],W)}return F.filter(X,W)};o.find=F;o.filter=F.filter;o.expr=F.selectors;o.expr[":"]=o.expr.filters;F.selectors.filters.hidden=function(T){return T.offsetWidth===0||T.offsetHeight===0};F.selectors.filters.visible=function(T){return T.offsetWidth>0||T.offsetHeight>0};F.selectors.filters.animated=function(T){return o.grep(o.timers,function(U){return T===U.elem}).length};o.multiFilter=function(V,T,U){if(U){V=":not("+V+")"}return F.matches(V,T)};o.dir=function(V,U){var T=[],W=V[U];while(W&&W!=document){if(W.nodeType==1){T.push(W)}W=W[U]}return T};o.nth=function(X,T,V,W){T=T||1;var U=0;for(;X;X=X[V]){if(X.nodeType==1&&++U==T){break}}return X};o.sibling=function(V,U){var T=[];for(;V;V=V.nextSibling){if(V.nodeType==1&&V!=U){T.push(V)}}return T};return;l.Sizzle=F})();o.event={add:function(I,F,H,K){if(I.nodeType==3||I.nodeType==8){return}if(I.setInterval&&I!=l){I=l}if(!H.guid){H.guid=this.guid++}if(K!==g){var G=H;H=this.proxy(G);H.data=K}var E=o.data(I,"events")||o.data(I,"events",{}),J=o.data(I,"handle")||o.data(I,"handle",function(){return typeof o!=="undefined"&&!o.event.triggered?o.event.handle.apply(arguments.callee.elem,arguments):g});J.elem=I;o.each(F.split(/\s+/),function(M,N){var O=N.split(".");N=O.shift();H.type=O.slice().sort().join(".");var L=E[N];if(o.event.specialAll[N]){o.event.specialAll[N].setup.call(I,K,O)}if(!L){L=E[N]={};if(!o.event.special[N]||o.event.special[N].setup.call(I,K,O)===false){if(I.addEventListener){I.addEventListener(N,J,false)}else{if(I.attachEvent){I.attachEvent("on"+N,J)}}}}L[H.guid]=H;o.event.global[N]=true});I=null},guid:1,global:{},remove:function(K,H,J){if(K.nodeType==3||K.nodeType==8){return}var G=o.data(K,"events"),F,E;if(G){if(H===g||(typeof H==="string"&&H.charAt(0)==".")){for(var I in G){this.remove(K,I+(H||""))}}else{if(H.type){J=H.handler;H=H.type}o.each(H.split(/\s+/),function(M,O){var Q=O.split(".");O=Q.shift();var N=RegExp("(^|\\.)"+Q.slice().sort().join(".*\\.")+"(\\.|$)");if(G[O]){if(J){delete G[O][J.guid]}else{for(var P in G[O]){if(N.test(G[O][P].type)){delete G[O][P]}}}if(o.event.specialAll[O]){o.event.specialAll[O].teardown.call(K,Q)}for(F in G[O]){break}if(!F){if(!o.event.special[O]||o.event.special[O].teardown.call(K,Q)===false){if(K.removeEventListener){K.removeEventListener(O,o.data(K,"handle"),false)}else{if(K.detachEvent){K.detachEvent("on"+O,o.data(K,"handle"))}}}F=null;delete G[O]}}})}for(F in G){break}if(!F){var L=o.data(K,"handle");if(L){L.elem=null}o.removeData(K,"events");o.removeData(K,"handle")}}},trigger:function(I,K,H,E){var G=I.type||I;if(!E){I=typeof I==="object"?I[h]?I:o.extend(o.Event(G),I):o.Event(G);if(G.indexOf("!")>=0){I.type=G=G.slice(0,-1);I.exclusive=true}if(!H){I.stopPropagation();if(this.global[G]){o.each(o.cache,function(){if(this.events&&this.events[G]){o.event.trigger(I,K,this.handle.elem)}})}}if(!H||H.nodeType==3||H.nodeType==8){return g}I.result=g;I.target=H;K=o.makeArray(K);K.unshift(I)}I.currentTarget=H;var J=o.data(H,"handle");if(J){J.apply(H,K)}if((!H[G]||(o.nodeName(H,"a")&&G=="click"))&&H["on"+G]&&H["on"+G].apply(H,K)===false){I.result=false}if(!E&&H[G]&&!I.isDefaultPrevented()&&!(o.nodeName(H,"a")&&G=="click")){this.triggered=true;try{H[G]()}catch(L){}}this.triggered=false;if(!I.isPropagationStopped()){var F=H.parentNode||H.ownerDocument;if(F){o.event.trigger(I,K,F,true)}}},handle:function(K){var J,E;K=arguments[0]=o.event.fix(K||l.event);K.currentTarget=this;var L=K.type.split(".");K.type=L.shift();J=!L.length&&!K.exclusive;var I=RegExp("(^|\\.)"+L.slice().sort().join(".*\\.")+"(\\.|$)");E=(o.data(this,"events")||{})[K.type];for(var G in E){var H=E[G];if(J||I.test(H.type)){K.handler=H;K.data=H.data;var F=H.apply(this,arguments);if(F!==g){K.result=F;if(F===false){K.preventDefault();K.stopPropagation()}}if(K.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(H){if(H[h]){return H}var F=H;H=o.Event(F);for(var G=this.props.length,J;G;){J=this.props[--G];H[J]=F[J]}if(!H.target){H.target=H.srcElement||document}if(H.target.nodeType==3){H.target=H.target.parentNode}if(!H.relatedTarget&&H.fromElement){H.relatedTarget=H.fromElement==H.target?H.toElement:H.fromElement}if(H.pageX==null&&H.clientX!=null){var I=document.documentElement,E=document.body;H.pageX=H.clientX+(I&&I.scrollLeft||E&&E.scrollLeft||0)-(I.clientLeft||0);H.pageY=H.clientY+(I&&I.scrollTop||E&&E.scrollTop||0)-(I.clientTop||0)}if(!H.which&&((H.charCode||H.charCode===0)?H.charCode:H.keyCode)){H.which=H.charCode||H.keyCode}if(!H.metaKey&&H.ctrlKey){H.metaKey=H.ctrlKey}if(!H.which&&H.button){H.which=(H.button&1?1:(H.button&2?3:(H.button&4?2:0)))}return H},proxy:function(F,E){E=E||function(){return F.apply(this,arguments)};E.guid=F.guid=F.guid||E.guid||this.guid++;return E},special:{ready:{setup:B,teardown:function(){}}},specialAll:{live:{setup:function(E,F){o.event.add(this,F[0],c)},teardown:function(G){if(G.length){var E=0,F=RegExp("(^|\\.)"+G[0]+"(\\.|$)");o.each((o.data(this,"events").live||{}),function(){if(F.test(this.type)){E++}});if(E<1){o.event.remove(this,G[0],c)}}}}}};o.Event=function(E){if(!this.preventDefault){return new o.Event(E)}if(E&&E.type){this.originalEvent=E;this.type=E.type}else{this.type=E}this.timeStamp=e();this[h]=true};function k(){return false}function u(){return true}o.Event.prototype={preventDefault:function(){this.isDefaultPrevented=u;var E=this.originalEvent;if(!E){return}if(E.preventDefault){E.preventDefault()}E.returnValue=false},stopPropagation:function(){this.isPropagationStopped=u;var E=this.originalEvent;if(!E){return}if(E.stopPropagation){E.stopPropagation()}E.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=u;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(F){var E=F.relatedTarget;while(E&&E!=this){try{E=E.parentNode}catch(G){E=this}}if(E!=this){F.type=F.data;o.event.handle.apply(this,arguments)}};o.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(F,E){o.event.special[E]={setup:function(){o.event.add(this,F,a,E)},teardown:function(){o.event.remove(this,F,a)}}});o.fn.extend({bind:function(F,G,E){return F=="unload"?this.one(F,G,E):this.each(function(){o.event.add(this,F,E||G,E&&G)})},one:function(G,H,F){var E=o.event.proxy(F||H,function(I){o(this).unbind(I,E);return(F||H).apply(this,arguments)});return this.each(function(){o.event.add(this,G,E,F&&H)})},unbind:function(F,E){return this.each(function(){o.event.remove(this,F,E)})},trigger:function(E,F){return this.each(function(){o.event.trigger(E,F,this)})},triggerHandler:function(E,G){if(this[0]){var F=o.Event(E);F.preventDefault();F.stopPropagation();o.event.trigger(F,G,this[0]);return F.result}},toggle:function(G){var E=arguments,F=1;while(F<E.length){o.event.proxy(G,E[F++])}return this.click(o.event.proxy(G,function(H){this.lastToggle=(this.lastToggle||0)%F;H.preventDefault();return E[this.lastToggle++].apply(this,arguments)||false}))},hover:function(E,F){return this.mouseenter(E).mouseleave(F)},ready:function(E){B();if(o.isReady){E.call(document,o)}else{o.readyList.push(E)}return this},live:function(G,F){var E=o.event.proxy(F);E.guid+=this.selector+G;o(document).bind(i(G,this.selector),this.selector,E);return this},die:function(F,E){o(document).unbind(i(F,this.selector),E?{guid:E.guid+this.selector+F}:null);return this}});function c(H){var E=RegExp("(^|\\.)"+H.type+"(\\.|$)"),G=true,F=[];o.each(o.data(this,"events").live||[],function(I,J){if(E.test(J.type)){var K=o(H.target).closest(J.data)[0];if(K){F.push({elem:K,fn:J})}}});F.sort(function(J,I){return o.data(J.elem,"closest")-o.data(I.elem,"closest")});o.each(F,function(){if(this.fn.call(this.elem,H,this.fn.data)===false){return(G=false)}});return G}function i(F,E){return["live",F,E.replace(/\./g,"`").replace(/ /g,"|")].join(".")}o.extend({isReady:false,readyList:[],ready:function(){if(!o.isReady){o.isReady=true;if(o.readyList){o.each(o.readyList,function(){this.call(document,o)});o.readyList=null}o(document).triggerHandler("ready")}}});var x=false;function B(){if(x){return}x=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);o.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);o.ready()}});if(document.documentElement.doScroll&&l==l.top){(function(){if(o.isReady){return}try{document.documentElement.doScroll("left")}catch(E){setTimeout(arguments.callee,0);return}o.ready()})()}}}o.event.add(l,"load",o.ready)}o.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(F,E){o.fn[E]=function(G){return G?this.bind(E,G):this.trigger(E)}});o(l).bind("unload",function(){for(var E in o.cache){if(E!=1&&o.cache[E].handle){o.event.remove(o.cache[E].handle.elem)}}});(function(){o.support={};var F=document.documentElement,G=document.createElement("script"),K=document.createElement("div"),J="script"+(new Date).getTime();K.style.display="none";K.innerHTML=' <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var H=K.getElementsByTagName("*"),E=K.getElementsByTagName("a")[0];if(!H||!H.length||!E){return}o.support={leadingWhitespace:K.firstChild.nodeType==3,tbody:!K.getElementsByTagName("tbody").length,objectAll:!!K.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!K.getElementsByTagName("link").length,style:/red/.test(E.getAttribute("style")),hrefNormalized:E.getAttribute("href")==="/a",opacity:E.style.opacity==="0.5",cssFloat:!!E.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};G.type="text/javascript";try{G.appendChild(document.createTextNode("window."+J+"=1;"))}catch(I){}F.insertBefore(G,F.firstChild);if(l[J]){o.support.scriptEval=true;delete l[J]}F.removeChild(G);if(K.attachEvent&&K.fireEvent){K.attachEvent("onclick",function(){o.support.noCloneEvent=false;K.detachEvent("onclick",arguments.callee)});K.cloneNode(true).fireEvent("onclick")}o(function(){var L=document.createElement("div");L.style.width=L.style.paddingLeft="1px";document.body.appendChild(L);o.boxModel=o.support.boxModel=L.offsetWidth===2;document.body.removeChild(L).style.display="none"})})();var w=o.support.cssFloat?"cssFloat":"styleFloat";o.props={"for":"htmlFor","class":"className","float":w,cssFloat:w,styleFloat:w,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};o.fn.extend({_load:o.fn.load,load:function(G,J,K){if(typeof G!=="string"){return this._load(G)}var I=G.indexOf(" ");if(I>=0){var E=G.slice(I,G.length);G=G.slice(0,I)}var H="GET";if(J){if(o.isFunction(J)){K=J;J=null}else{if(typeof J==="object"){J=o.param(J);H="POST"}}}var F=this;o.ajax({url:G,type:H,dataType:"html",data:J,complete:function(M,L){if(L=="success"||L=="notmodified"){F.html(E?o("<div/>").append(M.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(E):M.responseText)}if(K){F.each(K,[M.responseText,L,M])}}});return this},serialize:function(){return o.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?o.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(E,F){var G=o(this).val();return G==null?null:o.isArray(G)?o.map(G,function(I,H){return{name:F.name,value:I}}):{name:F.name,value:G}}).get()}});o.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(E,F){o.fn[F]=function(G){return this.bind(F,G)}});var r=e();o.extend({get:function(E,G,H,F){if(o.isFunction(G)){H=G;G=null}return o.ajax({type:"GET",url:E,data:G,success:H,dataType:F})},getScript:function(E,F){return o.get(E,null,F,"script")},getJSON:function(E,F,G){return o.get(E,F,G,"json")},post:function(E,G,H,F){if(o.isFunction(G)){H=G;G={}}return o.ajax({type:"POST",url:E,data:G,success:H,dataType:F})},ajaxSetup:function(E){o.extend(o.ajaxSettings,E)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return l.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(M){M=o.extend(true,M,o.extend(true,{},o.ajaxSettings,M));var W,F=/=\?(&|$)/g,R,V,G=M.type.toUpperCase();if(M.data&&M.processData&&typeof M.data!=="string"){M.data=o.param(M.data)}if(M.dataType=="jsonp"){if(G=="GET"){if(!M.url.match(F)){M.url+=(M.url.match(/\?/)?"&":"?")+(M.jsonp||"callback")+"=?"}}else{if(!M.data||!M.data.match(F)){M.data=(M.data?M.data+"&":"")+(M.jsonp||"callback")+"=?"}}M.dataType="json"}if(M.dataType=="json"&&(M.data&&M.data.match(F)||M.url.match(F))){W="jsonp"+r++;if(M.data){M.data=(M.data+"").replace(F,"="+W+"$1")}M.url=M.url.replace(F,"="+W+"$1");M.dataType="script";l[W]=function(X){V=X;I();L();l[W]=g;try{delete l[W]}catch(Y){}if(H){H.removeChild(T)}}}if(M.dataType=="script"&&M.cache==null){M.cache=false}if(M.cache===false&&G=="GET"){var E=e();var U=M.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+E+"$2");M.url=U+((U==M.url)?(M.url.match(/\?/)?"&":"?")+"_="+E:"")}if(M.data&&G=="GET"){M.url+=(M.url.match(/\?/)?"&":"?")+M.data;M.data=null}if(M.global&&!o.active++){o.event.trigger("ajaxStart")}var Q=/^(\w+:)?\/\/([^\/?#]+)/.exec(M.url);if(M.dataType=="script"&&G=="GET"&&Q&&(Q[1]&&Q[1]!=location.protocol||Q[2]!=location.host)){var H=document.getElementsByTagName("head")[0];var T=document.createElement("script");T.src=M.url;if(M.scriptCharset){T.charset=M.scriptCharset}if(!W){var O=false;T.onload=T.onreadystatechange=function(){if(!O&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){O=true;I();L();T.onload=T.onreadystatechange=null;H.removeChild(T)}}}H.appendChild(T);return g}var K=false;var J=M.xhr();if(M.username){J.open(G,M.url,M.async,M.username,M.password)}else{J.open(G,M.url,M.async)}try{if(M.data){J.setRequestHeader("Content-Type",M.contentType)}if(M.ifModified){J.setRequestHeader("If-Modified-Since",o.lastModified[M.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}J.setRequestHeader("X-Requested-With","XMLHttpRequest");J.setRequestHeader("Accept",M.dataType&&M.accepts[M.dataType]?M.accepts[M.dataType]+", */*":M.accepts._default)}catch(S){}if(M.beforeSend&&M.beforeSend(J,M)===false){if(M.global&&!--o.active){o.event.trigger("ajaxStop")}J.abort();return false}if(M.global){o.event.trigger("ajaxSend",[J,M])}var N=function(X){if(J.readyState==0){if(P){clearInterval(P);P=null;if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}}else{if(!K&&J&&(J.readyState==4||X=="timeout")){K=true;if(P){clearInterval(P);P=null}R=X=="timeout"?"timeout":!o.httpSuccess(J)?"error":M.ifModified&&o.httpNotModified(J,M.url)?"notmodified":"success";if(R=="success"){try{V=o.httpData(J,M.dataType,M)}catch(Z){R="parsererror"}}if(R=="success"){var Y;try{Y=J.getResponseHeader("Last-Modified")}catch(Z){}if(M.ifModified&&Y){o.lastModified[M.url]=Y}if(!W){I()}}else{o.handleError(M,J,R)}L();if(X){J.abort()}if(M.async){J=null}}}};if(M.async){var P=setInterval(N,13);if(M.timeout>0){setTimeout(function(){if(J&&!K){N("timeout")}},M.timeout)}}try{J.send(M.data)}catch(S){o.handleError(M,J,null,S)}if(!M.async){N()}function I(){if(M.success){M.success(V,R)}if(M.global){o.event.trigger("ajaxSuccess",[J,M])}}function L(){if(M.complete){M.complete(J,R)}if(M.global){o.event.trigger("ajaxComplete",[J,M])}if(M.global&&!--o.active){o.event.trigger("ajaxStop")}}return J},handleError:function(F,H,E,G){if(F.error){F.error(H,E,G)}if(F.global){o.event.trigger("ajaxError",[H,F,G])}},active:0,httpSuccess:function(F){try{return !F.status&&location.protocol=="file:"||(F.status>=200&&F.status<300)||F.status==304||F.status==1223}catch(E){}return false},httpNotModified:function(G,E){try{var H=G.getResponseHeader("Last-Modified");return G.status==304||H==o.lastModified[E]}catch(F){}return false},httpData:function(J,H,G){var F=J.getResponseHeader("content-type"),E=H=="xml"||!H&&F&&F.indexOf("xml")>=0,I=E?J.responseXML:J.responseText;if(E&&I.documentElement.tagName=="parsererror"){throw"parsererror"}if(G&&G.dataFilter){I=G.dataFilter(I,H)}if(typeof I==="string"){if(H=="script"){o.globalEval(I)}if(H=="json"){I=l["eval"]("("+I+")")}}return I},param:function(E){var G=[];function H(I,J){G[G.length]=encodeURIComponent(I)+"="+encodeURIComponent(J)}if(o.isArray(E)||E.jquery){o.each(E,function(){H(this.name,this.value)})}else{for(var F in E){if(o.isArray(E[F])){o.each(E[F],function(){H(F,this)})}else{H(F,o.isFunction(E[F])?E[F]():E[F])}}}return G.join("&").replace(/%20/g,"+")}});var m={},n,d=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function t(F,E){var G={};o.each(d.concat.apply([],d.slice(0,E)),function(){G[this]=F});return G}o.fn.extend({show:function(J,L){if(J){return this.animate(t("show",3),J,L)}else{for(var H=0,F=this.length;H<F;H++){var E=o.data(this[H],"olddisplay");this[H].style.display=E||"";if(o.css(this[H],"display")==="none"){var G=this[H].tagName,K;if(m[G]){K=m[G]}else{var I=o("<"+G+" />").appendTo("body");K=I.css("display");if(K==="none"){K="block"}I.remove();m[G]=K}o.data(this[H],"olddisplay",K)}}for(var H=0,F=this.length;H<F;H++){this[H].style.display=o.data(this[H],"olddisplay")||""}return this}},hide:function(H,I){if(H){return this.animate(t("hide",3),H,I)}else{for(var G=0,F=this.length;G<F;G++){var E=o.data(this[G],"olddisplay");if(!E&&E!=="none"){o.data(this[G],"olddisplay",o.css(this[G],"display"))}}for(var G=0,F=this.length;G<F;G++){this[G].style.display="none"}return this}},_toggle:o.fn.toggle,toggle:function(G,F){var E=typeof G==="boolean";return o.isFunction(G)&&o.isFunction(F)?this._toggle.apply(this,arguments):G==null||E?this.each(function(){var H=E?G:o(this).is(":hidden");o(this)[H?"show":"hide"]()}):this.animate(t("toggle",3),G,F)},fadeTo:function(E,G,F){return this.animate({opacity:G},E,F)},animate:function(I,F,H,G){var E=o.speed(F,H,G);return this[E.queue===false?"each":"queue"](function(){var K=o.extend({},E),M,L=this.nodeType==1&&o(this).is(":hidden"),J=this;for(M in I){if(I[M]=="hide"&&L||I[M]=="show"&&!L){return K.complete.call(this)}if((M=="height"||M=="width")&&this.style){K.display=o.css(this,"display");K.overflow=this.style.overflow}}if(K.overflow!=null){this.style.overflow="hidden"}K.curAnim=o.extend({},I);o.each(I,function(O,S){var R=new o.fx(J,K,O);if(/toggle|show|hide/.test(S)){R[S=="toggle"?L?"show":"hide":S](I)}else{var Q=S.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),T=R.cur(true)||0;if(Q){var N=parseFloat(Q[2]),P=Q[3]||"px";if(P!="px"){J.style[O]=(N||1)+P;T=((N||1)/R.cur(true))*T;J.style[O]=T+P}if(Q[1]){N=((Q[1]=="-="?-1:1)*N)+T}R.custom(T,N,P)}else{R.custom(T,S,"")}}});return true})},stop:function(F,E){var G=o.timers;if(F){this.queue([])}this.each(function(){for(var H=G.length-1;H>=0;H--){if(G[H].elem==this){if(E){G[H](true)}G.splice(H,1)}}});if(!E){this.dequeue()}return this}});o.each({slideDown:t("show",1),slideUp:t("hide",1),slideToggle:t("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(E,F){o.fn[E]=function(G,H){return this.animate(F,G,H)}});o.extend({speed:function(G,H,F){var E=typeof G==="object"?G:{complete:F||!F&&H||o.isFunction(G)&&G,duration:G,easing:F&&H||H&&!o.isFunction(H)&&H};E.duration=o.fx.off?0:typeof E.duration==="number"?E.duration:o.fx.speeds[E.duration]||o.fx.speeds._default;E.old=E.complete;E.complete=function(){if(E.queue!==false){o(this).dequeue()}if(o.isFunction(E.old)){E.old.call(this)}};return E},easing:{linear:function(G,H,E,F){return E+F*G},swing:function(G,H,E,F){return((-Math.cos(G*Math.PI)/2)+0.5)*F+E}},timers:[],fx:function(F,E,G){this.options=E;this.elem=F;this.prop=G;if(!E.orig){E.orig={}}}});o.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(o.fx.step[this.prop]||o.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(F){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var E=parseFloat(o.css(this.elem,this.prop,F));return E&&E>-10000?E:parseFloat(o.curCSS(this.elem,this.prop))||0},custom:function(I,H,G){this.startTime=e();this.start=I;this.end=H;this.unit=G||this.unit||"px";this.now=this.start;this.pos=this.state=0;var E=this;function F(J){return E.step(J)}F.elem=this.elem;if(F()&&o.timers.push(F)&&!n){n=setInterval(function(){var K=o.timers;for(var J=0;J<K.length;J++){if(!K[J]()){K.splice(J--,1)}}if(!K.length){clearInterval(n);n=g}},13)}},show:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());o(this.elem).show()},hide:function(){this.options.orig[this.prop]=o.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(H){var G=e();if(H||G>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var E=true;for(var F in this.options.curAnim){if(this.options.curAnim[F]!==true){E=false}}if(E){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(o.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){o(this.elem).hide()}if(this.options.hide||this.options.show){for(var I in this.options.curAnim){o.attr(this.elem.style,I,this.options.orig[I])}}this.options.complete.call(this.elem)}return false}else{var J=G-this.startTime;this.state=J/this.options.duration;this.pos=o.easing[this.options.easing||(o.easing.swing?"swing":"linear")](this.state,J,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};o.extend(o.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(E){o.attr(E.elem.style,"opacity",E.now)},_default:function(E){if(E.elem.style&&E.elem.style[E.prop]!=null){E.elem.style[E.prop]=E.now+E.unit}else{E.elem[E.prop]=E.now}}}});if(document.documentElement.getBoundingClientRect){o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}var G=this[0].getBoundingClientRect(),J=this[0].ownerDocument,F=J.body,E=J.documentElement,L=E.clientTop||F.clientTop||0,K=E.clientLeft||F.clientLeft||0,I=G.top+(self.pageYOffset||o.boxModel&&E.scrollTop||F.scrollTop)-L,H=G.left+(self.pageXOffset||o.boxModel&&E.scrollLeft||F.scrollLeft)-K;return{top:I,left:H}}}else{o.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return o.offset.bodyOffset(this[0])}o.offset.initialized||o.offset.initialize();var J=this[0],G=J.offsetParent,F=J,O=J.ownerDocument,M,H=O.documentElement,K=O.body,L=O.defaultView,E=L.getComputedStyle(J,null),N=J.offsetTop,I=J.offsetLeft;while((J=J.parentNode)&&J!==K&&J!==H){M=L.getComputedStyle(J,null);N-=J.scrollTop,I-=J.scrollLeft;if(J===G){N+=J.offsetTop,I+=J.offsetLeft;if(o.offset.doesNotAddBorder&&!(o.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(J.tagName))){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}F=G,G=J.offsetParent}if(o.offset.subtractsBorderForOverflowNotVisible&&M.overflow!=="visible"){N+=parseInt(M.borderTopWidth,10)||0,I+=parseInt(M.borderLeftWidth,10)||0}E=M}if(E.position==="relative"||E.position==="static"){N+=K.offsetTop,I+=K.offsetLeft}if(E.position==="fixed"){N+=Math.max(H.scrollTop,K.scrollTop),I+=Math.max(H.scrollLeft,K.scrollLeft)}return{top:N,left:I}}}o.offset={initialize:function(){if(this.initialized){return}var L=document.body,F=document.createElement("div"),H,G,N,I,M,E,J=L.style.marginTop,K='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';M={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(E in M){F.style[E]=M[E]}F.innerHTML=K;L.insertBefore(F,L.firstChild);H=F.firstChild,G=H.firstChild,I=H.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(G.offsetTop!==5);this.doesAddBorderForTableAndCells=(I.offsetTop===5);H.style.overflow="hidden",H.style.position="relative";this.subtractsBorderForOverflowNotVisible=(G.offsetTop===-5);L.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(L.offsetTop===0);L.style.marginTop=J;L.removeChild(F);this.initialized=true},bodyOffset:function(E){o.offset.initialized||o.offset.initialize();var G=E.offsetTop,F=E.offsetLeft;if(o.offset.doesNotIncludeMarginInBodyOffset){G+=parseInt(o.curCSS(E,"marginTop",true),10)||0,F+=parseInt(o.curCSS(E,"marginLeft",true),10)||0}return{top:G,left:F}}};o.fn.extend({position:function(){var I=0,H=0,F;if(this[0]){var G=this.offsetParent(),J=this.offset(),E=/^body|html$/i.test(G[0].tagName)?{top:0,left:0}:G.offset();J.top-=j(this,"marginTop");J.left-=j(this,"marginLeft");E.top+=j(G,"borderTopWidth");E.left+=j(G,"borderLeftWidth");F={top:J.top-E.top,left:J.left-E.left}}return F},offsetParent:function(){var E=this[0].offsetParent||document.body;while(E&&(!/^body|html$/i.test(E.tagName)&&o.css(E,"position")=="static")){E=E.offsetParent}return o(E)}});o.each(["Left","Top"],function(F,E){var G="scroll"+E;o.fn[G]=function(H){if(!this[0]){return null}return H!==g?this.each(function(){this==l||this==document?l.scrollTo(!F?H:o(l).scrollLeft(),F?H:o(l).scrollTop()):this[G]=H}):this[0]==l||this[0]==document?self[F?"pageYOffset":"pageXOffset"]||o.boxModel&&document.documentElement[G]||document.body[G]:this[0][G]}});o.each(["Height","Width"],function(I,G){var E=I?"Left":"Top",H=I?"Right":"Bottom",F=G.toLowerCase();o.fn["inner"+G]=function(){return this[0]?o.css(this[0],F,false,"padding"):null};o.fn["outer"+G]=function(K){return this[0]?o.css(this[0],F,false,K?"margin":"border"):null};var J=G.toLowerCase();o.fn[J]=function(K){return this[0]==l?document.compatMode=="CSS1Compat"&&document.documentElement["client"+G]||document.body["client"+G]:this[0]==document?Math.max(document.documentElement["client"+G],document.body["scroll"+G],document.documentElement["scroll"+G],document.body["offset"+G],document.documentElement["offset"+G]):K===g?(this.length?o.css(this[0],J):null):this.css(J,typeof K==="string"?K:K+"px")}})})();
670 test/vendor/qunit/jslitmus.js
@@ -0,0 +1,670 @@
+// JSLitmus.js
+//
+// History:
+// 2008-10-27: Initial release
+// 2008-11-09: Account for iteration loop overhead
+// 2008-11-13: Added OS detection
+// 2009-02-25: Create tinyURL automatically, shift-click runs tests in reverse
+//
+// Copyright (c) 2008-2009, Robert Kieffer
+// All Rights Reserved
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the
+// Software), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+(function() {
+ // Private methods and state
+
+ // Get platform info but don't go crazy trying to recognize everything
+ // that's out there. This is just for the major platforms and OSes.
+ var platform = 'unknown platform', ua = navigator.userAgent;
+
+ // Detect OS
+ var oses = ['Windows','iPhone OS','(Intel |PPC )?Mac OS X','Linux'].join('|');
+ var pOS = new RegExp('((' + oses + ') [^ \);]*)').test(ua) ? RegExp.$1 : null;
+ if (!pOS) pOS = new RegExp('((' + oses + ')[^ \);]*)').test(ua) ? RegExp.$1 : null;
+
+ // Detect browser
+ var pName = /(Chrome|MSIE|Safari|Opera|Firefox)/.test(ua) ? RegExp.$1 : null;
+
+ // Detect version
+ var vre = new RegExp('(Version|' + pName + ')[ \/]([^ ;]*)');
+ var pVersion = (pName && vre.test(ua)) ? RegExp.$2 : null;
+ var platform = (pOS && pName && pVersion) ? pName + ' ' + pVersion + ' on ' + pOS : 'unknown platform';
+
+ /**
+ * A smattering of methods that are needed to implement the JSLitmus testbed.
+ */
+ var jsl = {
+ /**
+ * Enhanced version of escape()
+ */
+ escape: function(s) {
+ s = s.replace(/,/g, '\\,');
+ s = escape(s);
+ s = s.replace(/\+/g, '%2b');
+ s = s.replace(/ /g, '+');
+ return s;
+ },
+
+ /**
+ * Get an element by ID.
+ */
+ $: function(id) {
+ return document.getElementById(id);
+ },
+
+ /**
+ * Null function
+ */
+ F: function() {},
+
+ /**
+ * Set the status shown in the UI
+ */
+ status: function(msg) {
+ var el = jsl.$('jsl_status');
+ if (el) el.innerHTML = msg || '';
+ },
+
+ /**
+ * Convert a number to an abbreviated string like, "15K" or "10M"
+ */
+ toLabel: function(n) {
+ if (n == Infinity) {
+ return 'Infinity';
+ } else if (n > 1e9) {
+ n = Math.round(n/1e8);
+ return n/10 + 'B';
+ } else if (n > 1e6) {
+ n = Math.round(n/1e5);
+ return n/10 + 'M';
+ } else if (n > 1e3) {
+ n = Math.round(n/1e2);
+ return n/10 + 'K';
+ }
+ return n;
+ },
+
+ /**
+ * Copy properties from src to dst
+ */
+ extend: function(dst, src) {
+ for (var k in src) dst[k] = src[k]; return dst;
+ },
+
+ /**
+ * Like Array.join(), but for the key-value pairs in an object
+ */
+ join: function(o, delimit1, delimit2) {
+ if (o.join) return o.join(delimit1); // If it's an array
+ var pairs = [];
+ for (var k in o) pairs.push(k + delimit1 + o[k]);
+ return pairs.join(delimit2);
+ },
+
+ /**
+ * Array#indexOf isn't supported in IE, so we use this as a cross-browser solution
+ */
+ indexOf: function(arr, o) {
+ if (arr.indexOf) return arr.indexOf(o);
+ for (var i = 0; i < this.length; i++) if (arr[i] === o) return i;
+ return -1;
+ }
+ };
+
+ /**
+ * Test manages a single test (created with
+ * JSLitmus.test())
+ *
+ * @private
+ */
+ var Test = function (name, f) {
+ if (!f) throw new Error('Undefined test function');
+ if (!(/function[^\(]*\(([^,\)]*)/).test(f.toString())) {
+ throw new Error('"' + name + '" test: Test is not a valid Function object');
+ }
+ this.loopArg = RegExp.$1;
+ this.name = name;
+ this.f = f;
+ };
+
+ jsl.extend(Test, /** @lends Test */ {
+ /** Calibration tests for establishing iteration loop overhead */
+ CALIBRATIONS: [
+ new Test('calibrating loop', function(count) {while (count--);}),
+ new Test('calibrating function', jsl.F)
+ ],
+
+ /**
+ * Run calibration tests. Returns true if calibrations are not yet
+ * complete (in which case calling code should run the tests yet again).
+ * onCalibrated - Callback to invoke when calibrations have finished
+ */
+ calibrate: function(onCalibrated) {
+ for (var i = 0; i < Test.CALIBRATIONS.length; i++) {
+ var cal = Test.CALIBRATIONS[i];
+ if (cal.running) return true;
+ if (!cal.count) {
+ cal.isCalibration = true;
+ cal.onStop = onCalibrated;
+ //cal.MIN_TIME = .1; // Do calibrations quickly
+ cal.run(2e4);
+ return true;
+ }
+ }
+ return false;
+ }
+ });
+
+ jsl.extend(Test.prototype, {/** @lends Test.prototype */
+ /** Initial number of iterations */
+ INIT_COUNT: 10,
+ /** Max iterations allowed (i.e. used to detect bad looping functions) */
+ MAX_COUNT: 1e9,
+ /** Minimum time a test should take to get valid results (secs) */
+ MIN_TIME: .5,
+
+ /** Callback invoked when test state changes */
+ onChange: jsl.F,
+
+ /** Callback invoked when test is finished */
+ onStop: jsl.F,
+
+ /**
+ * Reset test state
+ */
+ reset: function() {
+ delete this.count;
+ delete this.time;
+ delete this.running;
+ delete this.error;
+ },
+
+ /**
+ * Run the test (in a timeout). We use a timeout to make sure the browser
+ * has a chance to finish rendering any UI changes we've made, like
+ * updating the status message.
+ */
+ run: function(count) {
+ count = count || this.INIT_COUNT;
+ jsl.status(this.name + ' x ' + count);
+ this.running = true;
+ var me = this;
+ setTimeout(function() {me._run(count);}, 200);
+ },
+
+ /**
+ * The nuts and bolts code that actually runs a test
+ */
+ _run: function(count) {
+ var me = this;
+
+ // Make sure calibration tests have run
+ if (!me.isCalibration && Test.calibrate(function() {me.run(count);})) return;
+ this.error = null;
+
+ try {
+ var start, f = this.f, now, i = count;
+
+ // Start the timer
+ start = new Date();
+
+ // Now for the money shot. If this is a looping function ...
+ if (this.loopArg) {
+ // ... let it do the iteration itself
+ f(count);
+ } else {
+ // ... otherwise do the iteration for it
+ while (i--) f();
+ }
+
+ // Get time test took (in secs)
+ this.time = Math.max(1,new Date() - start)/1000;
+
+ // Store iteration count and per-operation time taken
+ this.count = count;
+ this.period = this.time/count;
+
+ // Do we need to do another run?
+ this.running = this.time <= this.MIN_TIME;
+
+ // ... if so, compute how many times we should iterate
+ if (this.running) {
+ // Bump the count to the nearest power of 2
+ var x = this.MIN_TIME/this.time;
+ var pow = Math.pow(2, Math.max(1, Math.ceil(Math.log(x)/Math.log(2))));
+ count *= pow;
+ if (count > this.MAX_COUNT) {
+ throw new Error('Max count exceeded. If this test uses a looping function, make sure the iteration loop is working properly.');
+ }
+ }
+ } catch (e) {
+ // Exceptions are caught and displayed in the test UI
+ this.reset();
+ this.error = e;
+ }
+
+ // Figure out what to do next
+ if (this.running) {
+ me.run(count);
+ } else {
+ jsl.status('');
+ me.onStop(me);
+ }
+
+ // Finish up
+ this.onChange(this);
+ },
+
+ /**
+ * Get the number of operations per second for this test.
+ *
+ * @param normalize if true, iteration loop overhead taken into account
+ */
+ getHz: function(/**Boolean*/ normalize) {
+ var p = this.period;
+
+ // Adjust period based on the calibration test time
+ if (normalize && !this.isCalibration) {
+ var cal = Test.CALIBRATIONS[this.loopArg ? 0 : 1];
+
+ // If the period is within 20% of the calibration time, then zero the
+ // it out
+ p = p < cal.period*1.2 ? 0 : p - cal.period;
+ }
+
+ return Math.round(1/p);
+ },
+
+ /**
+ * Get a friendly string describing the test
+ */
+ toString: function() {
+ return this.name + ' - ' + this.time/this.count + ' secs';
+ }
+ });
+
+ // CSS we need for the UI
+ var STYLESHEET = '<style> \
+ #jslitmus {font-family:sans-serif; font-size: 12px;} \
+ #jslitmus a {text-decoration: none;} \
+ #jslitmus a:hover {text-decoration: underline;} \
+ #jsl_status { \
+ margin-top: 10px; \
+ font-size: 10px; \
+ color: #888; \
+ } \
+ A IMG {border:none} \
+ #test_results { \
+ margin-top: 10px; \
+ font-size: 12px; \
+ font-family: sans-serif; \
+ border-collapse: collapse; \
+ border-spacing: 0px; \
+ } \
+ #test_results th, #test_results td { \
+ border: solid 1px #ccc; \
+ vertical-align: top; \
+ padding: 3px; \
+ } \
+ #test_results th { \
+ vertical-align: bottom; \
+ background-color: #ccc; \
+ padding: 1px; \
+ font-size: 10px; \
+ } \
+ #test_results #test_platform { \
+ color: #444; \
+ text-align:center; \
+ } \
+ #test_results .test_row { \
+ color: #006; \
+ cursor: pointer; \
+ } \
+ #test_results .test_nonlooping { \
+ border-left-style: dotted; \
+ border-left-width: 2px; \
+ } \
+ #test_results .test_looping { \
+ border-left-style: solid; \
+ border-left-width: 2px; \
+ } \
+ #test_results .test_name {white-space: nowrap;} \
+ #test_results .test_pending { \
+ } \
+ #test_results .test_running { \
+ font-style: italic; \
+ } \
+ #test_results .test_done {} \
+ #test_results .test_done { \
+ text-align: right; \
+ font-family: monospace; \
+ } \
+ #test_results .test_error {color: #600;} \
+ #test_results .test_error .error_head {font-weight:bold;} \
+ #test_results .test_error .error_body {font-size:85%;} \
+ #test_results .test_row:hover td { \
+ background-color: #ffc; \
+ text-decoration: underline; \
+ } \
+ #chart { \
+ margin: 10px 0px; \
+ width: 250px; \
+ } \
+ #chart img { \
+ border: solid 1px #ccc; \
+ margin-bottom: 5px; \
+ } \
+ #chart #tiny_url { \
+ height: 40px; \
+ width: 250px; \
+ } \
+ #jslitmus_credit { \
+ font-size: 10px; \
+ color: #888; \
+ margin-top: 8px; \
+ } \
+ </style>';
+
+ // HTML markup for the UI
+ var MARKUP = '<div id="jslitmus"> \
+ <button onclick="JSLitmus.runAll(event)">Run Tests</button> \
+ <button id="stop_button" disabled="disabled" onclick="JSLitmus.stop()">Stop Tests</button> \
+ <br \> \
+ <br \> \
+ <input type="checkbox" style="vertical-align: middle" id="test_normalize" checked="checked" onchange="JSLitmus.renderAll()""> Normalize results \
+ <table id="test_results"> \
+ <colgroup> \
+ <col /> \
+ <col width="100" /> \
+ </colgroup> \
+ <tr><th id="test_platform" colspan="2">' + platform + '</th></tr> \
+ <tr><th>Test</th><th>Ops/sec</th></tr> \
+ <tr id="test_row_template" class="test_row" style="display:none"> \
+ <td class="test_name"></td> \
+ <td class="test_result">Ready</td> \
+ </tr> \
+ </table> \
+ <div id="jsl_status"></div> \
+ <div id="chart" style="display:none"> \
+ <a id="chart_link" target="_blank"><img id="chart_image"></a> \
+ TinyURL (for chart): \
+ <iframe id="tiny_url" frameBorder="0" scrolling="no" src=""></iframe> \
+ </div> \
+ <a id="jslitmus_credit" title="JSLitmus home page" href="http://code.google.com/p/jslitmus" target="_blank">Powered by JSLitmus</a> \
+ </div>';
+
+ /**
+ * The public API for creating and running tests
+ */
+ window.JSLitmus = {
+ /** The list of all tests that have been registered with JSLitmus.test */
+ _tests: [],
+ /** The queue of tests that need to be run */
+ _queue: [],
+
+ /**
+ * The parsed query parameters the current page URL. This is provided as a
+ * convenience for test functions - it's not used by JSLitmus proper
+ */
+ params: {},
+
+ /**
+ * Initialize
+ */
+ _init: function() {
+ // Parse query params into JSLitmus.params[] hash
+ var match = (location + '').match(/([^?#]*)(#.*)?$/);
+ if (match) {
+ var pairs = match[1].split('&');
+ for (var i = 0; i < pairs.length; i++) {
+ var pair = pairs[i].split('=');
+ if (pair.length > 1) {
+ var key = pair.shift();
+ var value = pair.length > 1 ? pair.join('=') : pair[0];
+ this.params[key] = value;
+ }
+ }
+ }
+
+ // Write out the stylesheet. We have to do this here because IE
+ // doesn't honor sheets written after the document has loaded.
+ document.write(STYLESHEET);
+
+ // Setup the rest of the UI once the document is loaded
+ if (window.addEventListener) {
+ window.addEventListener('load', this._setup, false);
+ } else if (document.addEventListener) {
+ document.addEventListener('load', this._setup, false);
+ } else if (window.attachEvent) {
+ window.attachEvent('onload', this._setup);
+ }
+
+ return this;
+ },
+
+ /**
+ * Set up the UI
+ */
+ _setup: function() {
+ var el = jsl.$('jslitmus_container');
+ if (!el) document.body.appendChild(el = document.createElement('div'));
+
+ el.innerHTML = MARKUP;
+
+ // Render the UI for all our tests
+ for (var i=0; i < JSLitmus._tests.length; i++)
+ JSLitmus.renderTest(JSLitmus._tests[i]);
+ },
+
+ /**
+ * (Re)render all the test results
+ */
+ renderAll: function() {
+ for (var i = 0; i < JSLitmus._tests.length; i++)
+ JSLitmus.renderTest(JSLitmus._tests[i]);
+ JSLitmus.renderChart();
+ },
+
+ /**
+ * (Re)render the chart graphics
+ */
+ renderChart: function() {
+ var url = JSLitmus.chartUrl();
+ jsl.$('chart_link').href = url;
+ jsl.$('chart_image').src = url;
+ jsl.$('chart').style.display = '';
+
+ // Update the tiny URL
+ jsl.$('tiny_url').src = 'http://tinyurl.com/api-create.php?url='+escape(url);
+ },
+
+ /**
+ * (Re)render the results for a specific test
+ */
+ renderTest: function(test) {
+ // Make a new row if needed
+ if (!test._row) {
+ var trow = jsl.$('test_row_template');
+ if (!trow) return;
+
+ test._row = trow.cloneNode(true);
+ test._row.style.display = '';
+ test._row.id = '';
+ test._row.onclick = function() {JSLitmus._queueTest(test);};
+ test._row.title = 'Run ' + test.name + ' test';
+ trow.parentNode.appendChild(test._row);
+ test._row.cells[0].innerHTML = test.name;
+ }
+
+ var cell = test._row.cells[1];
+ var cns = [test.loopArg ? 'test_looping' : 'test_nonlooping'];
+
+ if (test.error) {
+ cns.push('test_error');
+ cell.innerHTML =
+ '<div class="error_head">' + test.error + '</div>' +
+ '<ul class="error_body"><li>' +
+ jsl.join(test.error, ': ', '</li><li>') +
+ '</li></ul>';
+ } else {
+ if (test.running) {
+ cns.push('test_running');
+ cell.innerHTML = 'running';
+ } else if (jsl.indexOf(JSLitmus._queue, test) >= 0) {
+ cns.push('test_pending');
+ cell.innerHTML = 'pending';
+ } else if (test.count) {
+ cns.push('test_done');
+ var hz = test.getHz(jsl.$('test_normalize').checked);
+ cell.innerHTML = hz != Infinity ? hz : '&infin;';
+ } else {
+ cell.innerHTML = 'ready';
+ }
+ }
+ cell.className = cns.join(' ');
+ },
+
+ /**
+ * Create a new test
+ */
+ test: function(name, f) {
+ // Create the Test object
+ var test = new Test(name, f);
+ JSLitmus._tests.push(test);
+
+ // Re-render if the test state changes
+ test.onChange = JSLitmus.renderTest;
+
+ // Run the next test if this one finished
+ test.onStop = function(test) {
+ if (JSLitmus.onTestFinish) JSLitmus.onTestFinish(test);
+ JSLitmus.currentTest = null;
+ JSLitmus._nextTest();
+ };
+
+ // Render the new test
+ this.renderTest(test);
+ },
+
+ /**
+ * Add all tests to the run queue
+ */
+ runAll: function(e) {
+ e = e || window.event;
+ var reverse = e && e.shiftKey, len = JSLitmus._tests.length;
+ for (var i = 0; i < len; i++) {
+ JSLitmus._queueTest(JSLitmus._tests[!reverse ? i : (len - i - 1)]);
+ }
+ },
+
+ /**
+ * Remove all tests from the run queue. The current test has to finish on
+ * it's own though
+ */
+ stop: function() {
+ while (JSLitmus._queue.length) {
+ var test = JSLitmus._queue.shift();
+ JSLitmus.renderTest(test);
+ }
+ },
+
+ /**
+ * Run the next test in the run queue
+ */
+ _nextTest: function() {
+ if (!JSLitmus.currentTest) {
+ var test = JSLitmus._queue.shift();
+ if (test) {
+ jsl.$('stop_button').disabled = false;
+ JSLitmus.currentTest = test;
+ test.run();
+ JSLitmus.renderTest(test);
+ if (JSLitmus.onTestStart) JSLitmus.onTestStart(test);
+ } else {
+ jsl.$('stop_button').disabled = true;
+ JSLitmus.renderChart();
+ }
+ }
+ },
+
+ /**
+ * Add a test to the run queue
+ */
+ _queueTest: function(test) {
+ if (jsl.indexOf(JSLitmus._queue, test) >= 0) return;
+ JSLitmus._queue.push(test);
+ JSLitmus.renderTest(test);
+ JSLitmus._nextTest();
+ },
+
+ /**
+ * Generate a Google Chart URL that shows the data for all tests
+ */
+ chartUrl: function() {
+ var n = JSLitmus._tests.length, markers = [], data = [];
+ var d, min = 0, max = -1e10;
+ var normalize = jsl.$('test_normalize').checked;
+
+ // Gather test data
+ for (var i=0; i < JSLitmus._tests.length; i++) {
+ var test = JSLitmus._tests[i];
+ if (test.count) {
+ var hz = test.getHz(normalize);
+ var v = hz != Infinity ? hz : 0;
+ data.push(v);
+ markers.push('t' + jsl.escape(test.name + '(' + jsl.toLabel(hz)+ ')') + ',000000,0,' +
+ markers.length + ',10');
+ max = Math.max(v, max);
+ }
+ }
+ if (markers.length <= 0) return null;
+
+ // Build chart title
+ var title = document.getElementsByTagName('title');
+ title = (title && title.length) ? title[0].innerHTML : null;
+ var chart_title = [];
+ if (title) chart_title.push(title);
+ chart_title.push('Ops/sec (' + platform + ')');
+
+ // Build labels
+ var labels = [jsl.toLabel(min), jsl.toLabel(max)];
+
+ var w = 250, bw = 15;
+ var bs = 5;
+ var h = markers.length*(bw + bs) + 30 + chart_title.length*20;
+
+ var params = {
+ chtt: escape(chart_title.join('|')),
+ chts: '000000,10',
+ cht: 'bhg', // chart type
+ chd: 't:' + data.join(','), // data set
+ chds: min + ',' + max, // max/min of data
+ chxt: 'x', // label axes
+ chxl: '0:|' + labels.join('|'), // labels
+ chsp: '0,1',
+ chm: markers.join('|'), // test names
+ chbh: [bw, 0, bs].join(','), // bar widths
+ // chf: 'bg,lg,0,eeeeee,0,eeeeee,.5,ffffff,1', // gradient
+ chs: w + 'x' + h
+ };
+ return 'http://chart.apis.google.com/chart?' + jsl.join(params, '=', '&');
+ }
+ };
+
+ JSLitmus._init();
+})();
196 test/vendor/qunit/qunit.css
@@ -0,0 +1,196 @@
+/** Font Family and Sizes */
+
+#qunit-tests, #qunit-header, .qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
+ font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial;
+}
+
+#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
+#qunit-tests { font-size: smaller; }
+
+
+/** Resets */
+
+#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
+ margin: 0;
+ padding: 0;
+}
+
+
+/** Header */
+
+#qunit-header, .qunit-header {
+ padding: 0.5em 0 0.5em 1em;
+
+ color: #8699a4;
+ background-color: #0d3349;
+
+ font-size: 1.5em;
+ line-height: 1em;
+ font-weight: normal;
+
+ border-radius: 15px 15px 0 0;
+ -moz-border-radius: 15px 15px 0 0;
+ -webkit-border-top-right-radius: 15px;
+ -webkit-border-top-left-radius: 15px;
+}
+
+#qunit-header a {
+ text-decoration: none;
+ color: #c2ccd1;
+}
+
+#qunit-header a:hover,
+#qunit-header a:focus {
+ color: #fff;
+}
+
+#qunit-banner {
+ height: 5px;
+}
+
+#qunit-testrunner-toolbar {
+ padding: 0em 0 0.5em 2em;
+}
+
+#qunit-userAgent {
+ padding: 0.5em 0 0.5em 2.5em;
+ background-color: #2b81af;
+ color: #fff;
+ text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
+}
+
+
+/** Tests: Pass/Fail */
+
+#qunit-tests {
+ list-style-position: inside;
+}
+
+#qunit-tests li {
+ padding: 0.4em 0.5em 0.4em 2.5em;
+ border-bottom: 1px solid #fff;
+ list-style-position: inside;
+}
+
+#qunit-tests li strong {
+ cursor: pointer;
+}
+
+#qunit-tests ol {
+ margin-top: 0.5em;
+ padding: 0.5em;
+
+ background-color: #fff;
+
+ border-radius: 15px;
+ -moz-border-radius: 15px;
+ -webkit-border-radius: 15px;
+
+ box-shadow: inset 0px 2px 13px #999;
+ -moz-box-shadow: inset 0px 2px 13px #999;
+ -webkit-box-shadow: inset 0px 2px 13px #999;
+}
+
+#qunit-tests table {
+ border-collapse: collapse;
+ margin-top: .2em;
+}
+
+#qunit-tests th {
+ text-align: right;
+ vertical-align: top;
+ padding: 0 .5em 0 0;
+}
+
+#qunit-tests td {
+ vertical-align: top;
+}
+
+#qunit-tests pre {
+ margin: 0;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+}
+
+#qunit-tests del {
+ background-color: #e0f2be;
+ color: #374e0c;
+ text-decoration: none;
+}
+
+#qunit-tests ins {
+ background-color: #ffcaca;
+ color: #500;
+ text-decoration: none;
+}
+
+/*** Test Counts */
+
+#qunit-tests b.counts { color: black; }
+#qunit-tests b.passed { color: #5E740B; }
+#qunit-tests b.failed { color: #710909; }
+
+#qunit-tests li li {
+ margin: 0.5em;
+ padding: 0.4em 0.5em 0.4em 0.5em;
+ background-color: #fff;
+ border-bottom: none;
+ list-style-position: inside;
+}
+
+/*** Passing Styles */
+
+#qunit-tests li li.pass {
+ color: #5E740B;
+ background-color: #fff;
+ border-left: 26px solid #C6E746;
+}
+
+#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
+#qunit-tests .pass .test-name { color: #366097; }
+
+#qunit-tests .pass .test-actual,
+#qunit-tests .pass .test-expected { color: #999999; }
+
+#qunit-banner.qunit-pass { background-color: #C6E746; }
+
+/*** Failing Styles */
+
+#qunit-tests li li.fail {
+ color: #710909;
+ background-color: #fff;
+ border-left: 26px solid #EE5757;
+}
+
+#qunit-tests .fail { color: #000000; background-color: #EE5757; }
+#qunit-tests .fail .test-name,
+#qunit-tests .fail .module-name { color: #000000; }
+
+#qunit-tests .fail .test-actual { color: #EE5757; }
+#qunit-tests .fail .test-expected { color: green; }
+
+#qunit-banner.qunit-fail,
+#qunit-testrunner-toolbar { background-color: #EE5757; }
+
+
+/** Footer */
+
+#qunit-testresult {