├── .gitignore
├── LICENSE
├── README.md
├── Rakefile
├── docs
├── docco.css
└── multimethod.html
├── index.js
├── multimethod-min.js
├── multimethod.js
├── package.json
└── test
├── multimethod-tests.js
├── test.html
└── vendor
├── jquery.js
├── qunit.css
├── qunit.js
└── underscore.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011 Kris Jordan
2 |
3 | Permission is hereby granted, free of charge, to any person
4 | obtaining a copy of this software and associated documentation
5 | files (the "Software"), to deal in the Software without
6 | restriction, including without limitation the rights to use,
7 | copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the
9 | Software is furnished to do so, subject to the following
10 | conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 | OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # What is multimethod.js?
2 |
3 | Multimethods are a functional programming control structure that allow you
4 | to dynamically build-up and manipulate the dispatching behavior of a
5 | polymorphic function. Inspired by clojure's multimethods, multimethod.js
6 | provides a functional alternative to classical, prototype based polymorphism.
7 | The multimethod.js library is 1kb minified, MIT licensed, and available on
8 | [GitHub](https://github.com/KrisJordan/multimethod-js).
9 |
10 | # Installation
11 |
12 | Install with `npm` for use in node.js based projects.
13 |
14 | npm install multimethod
15 | node
16 | > var multimethod = require('multimethod');
17 |
18 | For in-browser use you will need to grab
19 | [underscore.js](http://documentcloud.github.com/underscore/) and multimethod.js:
20 |
21 | - underscore.js
22 | - Development: http://documentcloud.github.com/underscore/underscore.js
23 | - Minified: http://documentcloud.github.com/underscore/underscore-min.js
24 | - multimethod.js
25 | - Development: https://raw.github.com/KrisJordan/multimethod-js/master/multimethod.js
26 | - Minified: https://raw.github.com/KrisJordan/multimethod-js/master/multimethod-min.js
27 |
28 | # API
29 |
30 | - Constructor: `multimethod`( [fn | string] ): No arg constructor uses an
31 | identity function for `dispatch`. Single arg constructor is a shortcut for
32 | calling `dispatch` with the same argument.
33 | - `dispatch`(fn | string): Sets the `multimethod`'s `dispatch` function. String
34 | values are transformed into a pluck function which projects a single
35 | property value from the first argurment.
36 | - `when`(match, fn | value): Add a `method` to be invoked when the `dispatch`
37 | return value matches 'match'. If a non-function `value` is provided it will
38 | be returned directly. Calling `when` with the same `match` value twice will
39 | override the previously registered `method`.
40 | - `remove`(match): Remove a `method` by it's `match` value.
41 | - `default`(fn | value): Catch-all case when no `method` match is found.
42 |
43 |
44 | # Motivating Examples
45 |
46 | Let's use the node.js REPL to build a few multimethods and see what they are
47 | capable of doing. In this first example we'll create a mulimethod that
48 | calculates the area of shapes instantiated with object literals.
49 |
50 | ```javascript
51 | > var multimethod = require('multimethod');
52 | > var area = multimethod()
53 | .dispatch(function(o) {
54 | return o.shape;
55 | })
56 | .when("square", function(o) {
57 | return Math.pow(o.side, 2);
58 | });
59 | > var aSquare = { "shape":"square", "side": 2 };
60 | > area( aSquare );
61 | 4
62 |
63 | > var aCircle = { "shape":"circle", "radius": 5 };
64 | > area( aCircle );
65 | undefined
66 |
67 | > area.default(function(o) {
68 | throw "Unknown shape: " + o.shape;
69 | });
70 | > area( aCircle );
71 | Unknown Shape: circle
72 |
73 | > area.when("circle", function(o) {
74 | return Math.PI * Math.pow(o.radius, 2);
75 | });
76 | > area( aCircle );
77 | 78.53981633974483
78 | > area( aSquare );
79 | 4
80 |
81 | > area.remove("circle");
82 | > area( aCircle );
83 | Unknown Shape: circle
84 | ```
85 |
86 | Notice how `dispatch` returns the value we'll match to a "method" registered
87 | with `when`. You can introduce, overwrite, and remove new methods dynamically at
88 | runtime. Fallback behavior can be established with a `default` function called
89 | when no methods match the dispatched value.
90 |
91 | A recursive Fibonacci function can be expressed naturally with a multimethod.
92 |
93 | ```javascript
94 | > var fib = multimethod()
95 | .when( 0, 0 )
96 | .when( 1, 1 )
97 | .default( function(n) {
98 | return fib(n-1) + fib(n-2);
99 | });
100 | > fib(20);
101 | 6765
102 | ```
103 |
104 | Notice, there is no `dispatch` specified. By default a multimethod will use
105 | the first argument it is invoked with to match the correct method to dispatch
106 | to.
107 |
108 | ```javascript
109 | > var hitPoints = multimethod()
110 | .dispatch(function(player){ return player.powerUp; })
111 | .when( {"type":"star"} , Infinity)
112 | .default(5);
113 |
114 | > var starPower = { "type":"star" },
115 | > mario = { "powerUp": starPower };
116 | > hitPoints(mario);
117 | Infinity
118 |
119 | > mario.powerUp = null;
120 | > hitPoints(mario);
121 | 5
122 |
123 | > var godModeCheat = function() { return starPower; };
124 | > hitPoints.dispatch(godModeCheat);
125 | > mario.powerUp;
126 | null
127 | > hitPoints(mario);
128 | Infinity
129 | ```
130 |
131 | In this last example notice how we are matching against an object. Matching
132 | is done using deep equality so objects and arrays are valid method matching
133 | criteria. Also notice how we can completely override our dispatch
134 | function to change the logic with which a multimethod evaluates its arguments
135 | for dispatch, or, in this case, ignores them!
136 |
137 | # Multimethod Dispatch Algorithm Overview
138 |
139 | 1. User calls multimethod with argument `anArgument`.
140 | 2. Multimethod calls its `dispatch` function with `anArgument`. The returned
141 | value is stored in `dispatchValue`.
142 | 3. Multimethod iterates through each 'method' registered with `when` and
143 | performs an equality test on the `dispatchValue` and each method's match
144 | value. If a match is found, set `matchFunction` to the method's function
145 | and go to step 5.
146 | 4. If no method match found, set `matchFunction` to the multimethod's `default`
147 | function.
148 | 5. Multimethod calls `matchFunction` with `anArgument`. The returned value
149 | is returned to the user who called the multimethod.
150 |
151 | # Detailed Walkthrough
152 |
153 | ## The Basics
154 |
155 | A `multimethod` is instantiated with the `multimethod` function.
156 |
157 | ```javascript
158 | var stopLightColor = multimethod();
159 | ```
160 |
161 | A `multimethod` has methods. A `method` is has two parts, its match value
162 | and its implementation function. Methods are added using `when`.
163 |
164 | ```javascript
165 | stopLightColor.when("go", function() { return "green"; })
166 | .when("stop", function() { return "red"; });
167 | ```
168 |
169 | You can call a `multimethod` just like any other function. It will dispatch
170 | based on the argument(s) passed in, invoke the matched `method`, and return
171 | the results of the `method` call.
172 |
173 | ```javascript
174 | console.log( stopLightColor("go") ); // "green"
175 | ```
176 |
177 | When no method matches control can fallback to a `default` method.
178 |
179 | ```javascript
180 | stopLightColor.default( function() { return "unknown"; } );
181 | console.log( stopLightColor("yield") ); // prints "unknown"
182 | ```
183 |
184 | A `multimethod` can handle new cases dynamically at run time.
185 |
186 | ```javascript
187 | stopLightColor.when("yield", function() { return "yellow"; });
188 | ```
189 |
190 | There is a shorter way for a `method` to return a plain value. Rather than
191 | passing an implementation function to `when`, pass the value.
192 |
193 | ```javascript
194 | stopLightColor.when("yield", "yellow");
195 | console.log( stopLightColor("yield") ); // prints "yellow"
196 | ```
197 |
198 | A `method` can be removed dynamically at run time, too.
199 |
200 | ```javascript
201 | stopLightColor.remove("go");
202 | console.log( stopLightColor("go") ); // prints "unknown"
203 | ```
204 |
205 | ## Dispatch Function
206 |
207 | Each `multimethod` call first invokes a `dispatch` function whose return value
208 | is used to match the correct `method` to call. The `dispatch` function is
209 | passed the arguments the `multimethod` is invoked with and returns a value
210 | to match against.
211 |
212 | The default `dispatch` function is an identity function.
213 | The basic `stopLightColor` examples could have been
214 | created with an explicit `dispatch` function.
215 |
216 | ```javascript
217 | var stopLightColor = multimethod()
218 | .dispatch(function(state){
219 | return state;
220 | })
221 | .when('go', 'green');
222 | console.log( stopLightColor('go') ); // green
223 | ```
224 |
225 | The power of the `multimethod` paradigm is the ability to dispatch with a
226 | user-defined function. This gives a `multimethod` its "polymorphic" powers.
227 | Unlike classical, object-oriented polymorphism where the compiler dispatches
228 | based on the type hierarchy, a `multimethod` can dispatch on any criteria.
229 |
230 | ```javascript
231 | var contacts = [
232 | {"name":"Jack", "service":"Twitter","handle": "@jack"},
233 | {"name":"Diane","service":"Email", "address":"d@g.com"},
234 | {"name":"John", "service":"Phone", "number": "919-919-9191"}
235 | ];
236 |
237 | var sendMessage = multimethod()
238 | .dispatch(function(contact, msg) {
239 | return contact.service;
240 | })
241 | .when("Twitter", function(contact, msg) {
242 | console.log("Tweet @"+contact.handle+":"+msg);
243 | })
244 | .when("Email", function(contact, msg) {
245 | console.log("Emailing "+contact.address+":"+msg);
246 | })
247 | .default(function(contact, msg) {
248 | console.log("Could not message " + contact.name);
249 | });
250 |
251 | // Blast a message
252 | contacts.forEach( function(contact) {
253 | sendMessage(contact, "Hello, world.");
254 | });
255 | ```
256 |
257 | Plucking a single property from an object is so commonly used as a `dispatch`
258 | function, like in the example above, there is a shortcut for this pattern.
259 | The following `dispatch` call is equivalent to above.
260 |
261 | ```javascript
262 | sendMessage.dispatch( 'service' );
263 | ```
264 |
265 | A `multimethod`'s `dispatch` is usually specified when constructed.
266 |
267 | ```javascript
268 | var sendMessage = multimethod('service');
269 | ```
270 |
271 | Just like `method`s can be added and removed from a `multimethod` at
272 | run time, the `dispatch` function can also be redefined at run time.
273 | Ponder the implications of that for a minute. It is really powerful and
274 | really dangerous. Don't shoot your eye out.
275 |
276 | ## Deep Equality Matching
277 |
278 | A `method`'s match value is compared to `dispatch`'s return value
279 | using the underscore.js
280 | [`isEqual`](http://documentcloud.github.com/underscore/#isEqual)
281 | function. Deep equality `method` matching enables concise expressivity.
282 | Contrast this with a traditional `switch` statement that is
283 | limited by JavaScript's === equality behavior.
284 |
285 | ```javascript
286 | var greatPairs = multimethod()
287 | .when( ["Salt", "Pepper"], "Shakers" )
288 | .when( [{"name":"Bonnie"}, {"name":"Clyde"}], "Robbers" );
289 | console.log( greatPairs( ["Salt", "Pepper"] ) ); // Shakers
290 | ```
291 |
292 | ## Related Work
293 |
294 | * Clojure's multimethod - http://clojure.org/multimethods
295 | * Pascal Coste Filtered Dispatch in Common Lisp - http://www.p-cos.net/documents/filtered-dispatch.pdf
296 |
297 | ## How-to Contribute
298 |
299 | * Submit bugs and feature requests on
300 | [GitHub Issues](https://github.com/KrisJordan/multimethod-js/issues) page.
301 | * Fork the repository and submit pull requests. Pull requests that update
302 | the test suite for coverage on changes will be brought in quickly.
303 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'closure-compiler'
3 |
4 | HEADER = /((^\s*\/\/.*\n)+)/
5 |
6 | desc "Use the Closure Compiler to compress multimethod.js"
7 | task :build do
8 | source = File.read('multimethod.js')
9 | header = source.match(HEADER)
10 | min = Closure::Compiler.new.compress(source)
11 | File.open('multimethod-min.js', 'w') do |file|
12 | file.write header[1].squeeze(' ') + min
13 | end
14 | end
15 |
16 | desc "Build the docco documentation"
17 | task :doc do
18 | sh "docco multimethod.js"
19 | end
20 |
--------------------------------------------------------------------------------
/docs/docco.css:
--------------------------------------------------------------------------------
1 | /*--------------------- Layout and Typography ----------------------------*/
2 | body {
3 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
4 | font-size: 15px;
5 | line-height: 22px;
6 | color: #252519;
7 | margin: 0; padding: 0;
8 | }
9 | a {
10 | color: #261a3b;
11 | }
12 | a:visited {
13 | color: #261a3b;
14 | }
15 | p {
16 | margin: 0 0 15px 0;
17 | }
18 | h1, h2, h3, h4, h5, h6 {
19 | margin: 0px 0 15px 0;
20 | }
21 | h1 {
22 | margin-top: 40px;
23 | }
24 | #container {
25 | position: relative;
26 | }
27 | #background {
28 | position: fixed;
29 | top: 0; left: 525px; right: 0; bottom: 0;
30 | background: #f5f5ff;
31 | border-left: 1px solid #e5e5ee;
32 | z-index: -1;
33 | }
34 | #jump_to, #jump_page {
35 | background: white;
36 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
37 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
38 | font: 10px Arial;
39 | text-transform: uppercase;
40 | cursor: pointer;
41 | text-align: right;
42 | }
43 | #jump_to, #jump_wrapper {
44 | position: fixed;
45 | right: 0; top: 0;
46 | padding: 5px 10px;
47 | }
48 | #jump_wrapper {
49 | padding: 0;
50 | display: none;
51 | }
52 | #jump_to:hover #jump_wrapper {
53 | display: block;
54 | }
55 | #jump_page {
56 | padding: 5px 0 3px;
57 | margin: 0 0 25px 25px;
58 | }
59 | #jump_page .source {
60 | display: block;
61 | padding: 5px 10px;
62 | text-decoration: none;
63 | border-top: 1px solid #eee;
64 | }
65 | #jump_page .source:hover {
66 | background: #f5f5ff;
67 | }
68 | #jump_page .source:first-child {
69 | }
70 | table td {
71 | border: 0;
72 | outline: 0;
73 | }
74 | td.docs, th.docs {
75 | max-width: 450px;
76 | min-width: 450px;
77 | min-height: 5px;
78 | padding: 10px 25px 1px 50px;
79 | overflow-x: hidden;
80 | vertical-align: top;
81 | text-align: left;
82 | }
83 | .docs pre {
84 | margin: 15px 0 15px;
85 | padding-left: 15px;
86 | }
87 | .docs p tt, .docs p code {
88 | background: #f8f8ff;
89 | border: 1px solid #dedede;
90 | font-size: 12px;
91 | padding: 0 0.2em;
92 | }
93 | .pilwrap {
94 | position: relative;
95 | }
96 | .pilcrow {
97 | font: 12px Arial;
98 | text-decoration: none;
99 | color: #454545;
100 | position: absolute;
101 | top: 3px; left: -20px;
102 | padding: 1px 2px;
103 | opacity: 0;
104 | -webkit-transition: opacity 0.2s linear;
105 | }
106 | td.docs:hover .pilcrow {
107 | opacity: 1;
108 | }
109 | td.code, th.code {
110 | padding: 14px 15px 16px 25px;
111 | width: 100%;
112 | vertical-align: top;
113 | background: #f5f5ff;
114 | border-left: 1px solid #e5e5ee;
115 | }
116 | pre, tt, code {
117 | font-size: 12px; line-height: 18px;
118 | font-family: Monaco, Consolas, "Lucida Console", monospace;
119 | margin: 0; padding: 0;
120 | }
121 |
122 |
123 | /*---------------------- Syntax Highlighting -----------------------------*/
124 | td.linenos { background-color: #f0f0f0; padding-right: 10px; }
125 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
126 | body .hll { background-color: #ffffcc }
127 | body .c { color: #408080; font-style: italic } /* Comment */
128 | body .err { border: 1px solid #FF0000 } /* Error */
129 | body .k { color: #954121 } /* Keyword */
130 | body .o { color: #666666 } /* Operator */
131 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
132 | body .cp { color: #BC7A00 } /* Comment.Preproc */
133 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */
134 | body .cs { color: #408080; font-style: italic } /* Comment.Special */
135 | body .gd { color: #A00000 } /* Generic.Deleted */
136 | body .ge { font-style: italic } /* Generic.Emph */
137 | body .gr { color: #FF0000 } /* Generic.Error */
138 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
139 | body .gi { color: #00A000 } /* Generic.Inserted */
140 | body .go { color: #808080 } /* Generic.Output */
141 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
142 | body .gs { font-weight: bold } /* Generic.Strong */
143 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
144 | body .gt { color: #0040D0 } /* Generic.Traceback */
145 | body .kc { color: #954121 } /* Keyword.Constant */
146 | body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
147 | body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
148 | body .kp { color: #954121 } /* Keyword.Pseudo */
149 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
150 | body .kt { color: #B00040 } /* Keyword.Type */
151 | body .m { color: #666666 } /* Literal.Number */
152 | body .s { color: #219161 } /* Literal.String */
153 | body .na { color: #7D9029 } /* Name.Attribute */
154 | body .nb { color: #954121 } /* Name.Builtin */
155 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
156 | body .no { color: #880000 } /* Name.Constant */
157 | body .nd { color: #AA22FF } /* Name.Decorator */
158 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */
159 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
160 | body .nf { color: #0000FF } /* Name.Function */
161 | body .nl { color: #A0A000 } /* Name.Label */
162 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
163 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */
164 | body .nv { color: #19469D } /* Name.Variable */
165 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
166 | body .w { color: #bbbbbb } /* Text.Whitespace */
167 | body .mf { color: #666666 } /* Literal.Number.Float */
168 | body .mh { color: #666666 } /* Literal.Number.Hex */
169 | body .mi { color: #666666 } /* Literal.Number.Integer */
170 | body .mo { color: #666666 } /* Literal.Number.Oct */
171 | body .sb { color: #219161 } /* Literal.String.Backtick */
172 | body .sc { color: #219161 } /* Literal.String.Char */
173 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
174 | body .s2 { color: #219161 } /* Literal.String.Double */
175 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
176 | body .sh { color: #219161 } /* Literal.String.Heredoc */
177 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
178 | body .sx { color: #954121 } /* Literal.String.Other */
179 | body .sr { color: #BB6688 } /* Literal.String.Regex */
180 | body .s1 { color: #219161 } /* Literal.String.Single */
181 | body .ss { color: #19469D } /* Literal.String.Symbol */
182 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */
183 | body .vc { color: #19469D } /* Name.Variable.Class */
184 | body .vg { color: #19469D } /* Name.Variable.Global */
185 | body .vi { color: #19469D } /* Name.Variable.Instance */
186 | body .il { color: #666666 } /* Literal.Number.Integer.Long */
--------------------------------------------------------------------------------
/docs/multimethod.html:
--------------------------------------------------------------------------------
1 |
multimethod.js
multimethod.js multimethod.js 0.1.0
2 |
3 | (c) 2011 Kris Jordan
4 |
5 | multimethod
is freely distributable under the MIT license.
6 | For details and documentation:
7 | http://krisjordan.com/multimethod-js
Multimethods are a functional programming control structure for dispatching
8 | function calls with user-defined criteria that can be changed at run time.
9 | Inspired by clojure's multimethods, multimethod.js provides an alternative to
10 | classical, prototype-chain based polymorphism.
Internal Utility Functions No operation function used by default by default
.
var noop = function () {}; Identity dispatch
function. Default value of dispatch
.
var identity = function ( a ) { return a ; }; A method
in multimethod
is a (match value, function) pair stored in
11 | an array. indexOf
takes a value and array of methods and returns the
12 | index of the method whose value is equal to the first argument. If no
13 | match is found, false is returned.
var indexOf = function ( value , methods ) {
14 | for ( var i in methods ) {
15 | var matches = methods [ i ][ 0 ];
16 | if ( _ ( value ). isEqual ( matches )) {
17 | return i ;
18 | }
19 | }
20 | return false ;
21 | } Given a dispatch value
and array of method
s, return the function
22 | of the method
whose match value corresponds to a dispatch value.
var match = function ( value , methods ) {
23 | var index = indexOf ( value , methods );
24 | if ( index !== false ) {
25 | return methods [ index ][ 1 ];
26 | } else {
27 | return false ;
28 | }
29 | } Simple, consistent helper that returns a native value or invokes a function
30 | and returns its return value. Used by when
and default
allowing
31 | short-hand notation for returning values rather than calling functions.
var toValue = function ( subject , args ) {
32 | if ( _ . isFunction ( subject )) {
33 | return subject . apply ( this , args );
34 | } else {
35 | return subject ;
36 | }
37 | }; Plucking a single property value from an object in dispatch
is commonly
38 | used. The internal pluck
function returns a function suitable for use
39 | by dispatch
for just that purpose.
var pluck = function ( property ) {
40 | return function ( object ) {
41 | return object [ property ];
42 | }
43 | }; Implementation multimethod
is a higher-order function that returns a closure with
44 | methods to control its behavior.
var multimethod = function ( dispatch ) { Private Properties _dispatch
holds either a dispatch function or a string
45 | corresponding to the property name whose value will be plucked
46 | and used as the dispatch
criteria.
_methods
is a an array of method
arrays. A method
is
47 | [ matchValue, implementation ].
_default
is the fallback method when a multimethod
is called
48 | and matches no other method.
The fundamental control flow of the multimethod
is implemented
49 | in _lookup
. First we invoke the dispatch function, this gives
50 | us our match criteria. Then we match a method based on the criteria
51 | or return the default method.
var _lookup = function () {
52 | var criteria = _dispatch . apply ( this , arguments ),
53 | method = match ( criteria , _methods );
54 | if ( method !== false ) {
55 | return method ;
56 | } else {
57 | return _default ;
58 | }
59 | }; The result of calling multimethod
's "factory" function is this function.
var returnFn = function () {
60 | var method = _lookup . apply ( this , arguments );
61 | return toValue . call ( this , method , arguments );
62 | }; Member Methods / API dispatch
is the accessor to the multimethod
's _dispatch
function.
63 | When called with a string we create an anonymous pluck function as a
64 | shorthand.
returnFn [ 'dispatch' ] = function ( dispatch ) {
65 | if ( _ . isFunction ( dispatch )) {
66 | _dispatch = dispatch ;
67 | } else if ( _ . isString ( dispatch )) {
68 | _dispatch = pluck ( dispatch );
69 | } else {
70 | throw "dispatch requires a function or a string." ;
71 | }
72 | return this ;
73 | } If multimethod
is called/"constructed" with a dispatch
value we go ahead and set
74 | it up here. Otherwise dispatch
is the identity
function.
returnFn . dispatch ( dispatch || identity ); when
introduces new method
s to a multimethod
. If the
75 | matchValue
has already been registered the new method will
76 | overwrite the old method.
returnFn [ 'when' ] = function ( matchValue , fn ) {
77 | var index = indexOf ( matchValue , _methods );
78 | if ( index !== false ) {
79 | _methods [ index ] = [ matchValue , fn ];
80 | } else {
81 | _methods . push ([ matchValue , fn ]);
82 | }
83 | return this ;
84 | } remove
will unregister a method
based on matchValue
returnFn [ 'remove' ] = function ( matchValue ) {
85 | var index = indexOf ( matchValue , _methods );
86 | if ( index !== false ) {
87 | _methods . splice ( index , 1 );
88 | }
89 | return this ;
90 | } default
is an accessor to control the _default
, fallback method
91 | that is called when no match is found when the multimethod
is
92 | invoked and dispatched.
returnFn [ 'default' ] = function ( method ) {
93 | _default = method ;
94 | return this ;
95 | } Our multimethod
instance/closure is fully setup now, return!
The following snippet courtesy of underscore.js.
97 | Export multimethod
to the window/exports namespace.
if ( typeof exports !== 'undefined' ) {
98 | if ( typeof module !== 'undefined' && module . exports ) {
99 | exports = module . exports = multimethod ;
100 | var _ = require ( 'underscore' );
101 | }
102 | exports . multimethod = multimethod ;
103 | } else if ( typeof define === 'function' && define . amd ) {
104 | define ( 'multimethod' , function () {
105 | return multimethod ;
106 | });
107 | } else {
108 | this [ 'multimethod' ] = multimethod ;
109 | var _ = this [ '_' ];
110 | }
111 |
112 | multimethod . version = '0.1.0' ;
113 |
114 | }). call ( this );
115 |
116 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | module.exports = require('./multimethod');
2 |
--------------------------------------------------------------------------------
/multimethod-min.js:
--------------------------------------------------------------------------------
1 | // multimethod.js 0.1.0
2 | //
3 | // (c) 2011 Kris Jordan
4 | //
5 | // Multimethod is freely distributable under the MIT license.
6 | // For details and documentation:
7 | // [http://krisjordan.com/multimethod-js](http://krisjordan.com/multimethod-js)
8 | (function(){var j=function(){},k=function(g){return g},h=function(g,c){for(var d in c){var b=c[d][0];if(f(g).isEqual(b))return d}return false},l=function(b){return function(c){return c[b]}},b=function(b){var c,d=[],i=j,m=function(){var a=c.apply(this,arguments),a=h(a,d),a=a!==false?d[a][1]:false;return a!==false?a:i},e=function(){var a=m.apply(this,arguments);return f.isFunction(a)?a.apply(this,arguments):a};e.dispatch=function(a){if(f.isFunction(a))c=a;else if(f.isString(a))c=l(a);else throw"dispatch requires a function or a string.";
9 | return this};e.dispatch(b||k);e.when=function(a,b){var c=h(a,d);c!==false?d[c]=[a,b]:d.push([a,b]);return this};e.remove=function(a){a=h(a,d);a!==false&&d.splice(a,1);return this};e["default"]=function(a){i=a;return this};return e};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports){exports=module.exports=b;var f=require("underscore")}exports.multimethod=b}else typeof define==="function"&&define.amd?define("multimethod",function(){return b}):(this.multimethod=b,f=this._);
10 | b.version="0.1.0"}).call(this);
11 |
--------------------------------------------------------------------------------
/multimethod.js:
--------------------------------------------------------------------------------
1 | // multimethod.js 0.1.0
2 | //
3 | // (c) 2011 Kris Jordan
4 | //
5 | // `multimethod` is freely distributable under the MIT license.
6 | // For details and documentation:
7 | // [http://krisjordan.com/multimethod-js](http://krisjordan.com/multimethod-js)
8 |
9 | (function() {
10 |
11 | // Multimethods are a functional programming control structure for dispatching
12 | // function calls with user-defined criteria that can be changed at run time.
13 | // Inspired by clojure's multimethods, multimethod.js provides an alternative to
14 | // classical, prototype-chain based polymorphism.
15 |
16 | // ## Internal Utility Functions
17 |
18 | // No operation function used by default by `default`.
19 | var noop = function() {};
20 |
21 | // Identity `dispatch` function. Default value of `dispatch`.
22 | var identity = function(a) { return a; };
23 |
24 | // A `method` in `multimethod` is a (match value, function) pair stored in
25 | // an array. `indexOf` takes a value and array of methods and returns the
26 | // index of the method whose value is equal to the first argument. If no
27 | // match is found, false is returned.
28 | var indexOf = function(value, methods) {
29 | for(var i in methods) {
30 | var matches = methods[i][0];
31 | if(_(value).isEqual(matches)) {
32 | return i;
33 | }
34 | }
35 | return false;
36 | }
37 |
38 | // Given a dispatch `value` and array of `method`s, return the function
39 | // of the `method` whose match value corresponds to a dispatch value.
40 | var match = function(value, methods) {
41 | var index = indexOf(value, methods);
42 | if(index !== false) {
43 | return methods[index][1];
44 | } else {
45 | return false;
46 | }
47 | }
48 |
49 | // Simple, consistent helper that returns a native value or invokes a function
50 | // and returns its return value. Used by `when` and `default` allowing
51 | // short-hand notation for returning values rather than calling functions.
52 | var toValue = function(subject, args) {
53 | if(_.isFunction(subject)) {
54 | return subject.apply(this, args);
55 | } else {
56 | return subject;
57 | }
58 | };
59 |
60 | // Plucking a single property value from an object in `dispatch` is commonly
61 | // used. The internal `pluck` function returns a function suitable for use
62 | // by `dispatch` for just that purpose.
63 | var pluck = function(property) {
64 | return function(object) {
65 | return object[property];
66 | }
67 | };
68 |
69 |
70 | // ## Implementation
71 |
72 | // `multimethod` is a higher-order function that returns a closure with
73 | // methods to control its behavior.
74 | var multimethod = function(dispatch) {
75 |
76 | // ### Private Properties
77 |
78 | // `_dispatch` holds either a dispatch function or a string
79 | // corresponding to the property name whose value will be plucked
80 | // and used as the `dispatch` criteria.
81 | var _dispatch,
82 | // `_methods` is a an array of `method` arrays. A `method` is
83 | // [ matchValue, implementation ].
84 | _methods = [],
85 | // `_default` is the fallback method when a `multimethod` is called
86 | // and matches no other method.
87 | _default = noop;
88 |
89 | // The fundamental control flow of the `multimethod` is implemented
90 | // in `_lookup`. First we invoke the dispatch function, this gives
91 | // us our match criteria. Then we match a method based on the criteria
92 | // or return the default method.
93 | var _lookup = function() {
94 | var criteria = _dispatch.apply(this, arguments),
95 | method = match(criteria, _methods);
96 | if(method !== false) {
97 | return method;
98 | } else {
99 | return _default;
100 | }
101 | };
102 |
103 | // The result of calling `multimethod`'s "factory" function is this function.
104 | var returnFn = function() {
105 | var method = _lookup.apply(this, arguments);
106 | return toValue.call(this, method, arguments);
107 | };
108 |
109 | // ### Member Methods / API
110 |
111 | // `dispatch` is the accessor to the `multimethod`'s `_dispatch` function.
112 | // When called with a string we create an anonymous pluck function as a
113 | // shorthand.
114 | returnFn['dispatch'] = function(dispatch) {
115 | if(_.isFunction(dispatch)) {
116 | _dispatch = dispatch;
117 | } else if(_.isString(dispatch)) {
118 | _dispatch = pluck(dispatch);
119 | } else {
120 | throw "dispatch requires a function or a string.";
121 | }
122 | return this;
123 | }
124 | // If `multimethod` is called/"constructed" with a `dispatch` value we go ahead and set
125 | // it up here. Otherwise `dispatch` is the `identity` function.
126 | returnFn.dispatch(dispatch || identity);
127 |
128 | // `when` introduces new `method`s to a `multimethod`. If the
129 | // `matchValue` has already been registered the new method will
130 | // overwrite the old method.
131 | returnFn['when'] = function(matchValue, fn) {
132 | var index = indexOf(matchValue, _methods);
133 | if(index !== false) {
134 | _methods[index] = [matchValue, fn];
135 | } else {
136 | _methods.push([matchValue, fn]);
137 | }
138 | return this;
139 | }
140 |
141 | // `remove` will unregister a `method` based on matchValue
142 | returnFn['remove'] = function(matchValue) {
143 | var index = indexOf(matchValue, _methods);
144 | if(index !== false) {
145 | _methods.splice(index, 1);
146 | }
147 | return this;
148 | }
149 |
150 | // `default` is an accessor to control the `_default`, fallback method
151 | // that is called when no match is found when the `multimethod` is
152 | // invoked and dispatched.
153 | returnFn['default'] = function(method) {
154 | _default = method;
155 | return this;
156 | }
157 |
158 | // Our `multimethod` instance/closure is fully setup now, return!
159 | return returnFn;
160 | };
161 |
162 | // The following snippet courtesy of underscore.js.
163 | // Export `multimethod` to the window/exports namespace.
164 | if (typeof exports !== 'undefined') {
165 | if (typeof module !== 'undefined' && module.exports) {
166 | exports = module.exports = multimethod;
167 | var _ = require('underscore');
168 | }
169 | exports.multimethod = multimethod;
170 | } else if (typeof define === 'function' && define.amd) {
171 | define('multimethod', function() {
172 | return multimethod;
173 | });
174 | } else {
175 | this['multimethod'] = multimethod;
176 | var _ = this['_'];
177 | }
178 |
179 | multimethod.version = '0.1.0';
180 |
181 | }).call(this);
182 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Kris Jordan (http://krisjordan.com)",
3 | "name": "multimethod",
4 | "description": "Multimethods for JavaScript",
5 | "version": "0.1.0",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/KrisJordan/multimethod-js.git"
9 | },
10 | "engines": {
11 | "node": "~0.6.0"
12 | },
13 | "dependencies": {
14 | "underscore": "1.2.1"
15 | },
16 | "devDependencies": {}
17 | }
18 |
--------------------------------------------------------------------------------
/test/multimethod-tests.js:
--------------------------------------------------------------------------------
1 | $(document).ready(function() {
2 |
3 | module("Multimethods");
4 |
5 | var helpers = {
6 | "plus1": function(n) { return n + 1; },
7 | "sum": function(a,b) { return a + b; },
8 | "product": function(a,b) { return a * b; }
9 | }
10 |
11 | test("identity default", function() {
12 | var mm = multimethod();
13 | equals(mm(1), undefined);
14 | });
15 |
16 | test("identity dispatch function", function() {
17 | var mm = multimethod().when(1,helpers.plus1);
18 | equals(mm(1),2);
19 | });
20 |
21 | test("default dispatch function", function() {
22 | var mm = multimethod().default(helpers.plus1);
23 | equals(mm(1),2);
24 | });
25 |
26 | test("when returns primitive values", function() {
27 | var mm = multimethod().when(1,2);
28 | equals(mm(1),2);
29 |
30 | var mm = multimethod().when(1,true);
31 | equals(mm(1),true);
32 |
33 | var mm = multimethod().when(1,"string");
34 | equals(mm(1),"string");
35 | });
36 |
37 | test("when chains and selects correct value", function() {
38 | var mm = multimethod()
39 | .when(1,"one")
40 | .when(2,"two")
41 | .when(3,"three");
42 | equals(mm(1),"one");
43 | equals(mm(2),"two");
44 | equals(mm(3),"three");
45 | });
46 |
47 | test("multiple arguments", function() {
48 | var mm = multimethod(function(a, b) { return [a, b]; })
49 | .when([1,1], helpers.sum)
50 | .when([3,3], helpers.product);
51 | equals(mm(1,1),2);
52 | equals(mm(3,3),9);
53 | });
54 |
55 | test("modify dispatch function", function() {
56 | var mm = multimethod()
57 | .dispatch(helpers.plus1)
58 | .when(2,helpers.plus1);
59 | equals(mm(1),2);
60 | });
61 |
62 | test("override method", function() {
63 | var mm = multimethod()
64 | .when(1, 1)
65 | .when(1, 2);
66 | equals(mm(1),2);
67 | });
68 |
69 | test("remove method", function() {
70 | var mm = multimethod()
71 | .when(1,1)
72 | .default(2)
73 | .remove(1);
74 | equals(mm(1),2);
75 | });
76 |
77 | test("pluck string dispatch", function() {
78 | var bornOn = multimethod('type')
79 | .when('person',function(person) { return person.yearBorn; })
80 | .when('car', function(car) { return car.yearBuilt; })
81 | equals(bornOn({'type':'person','yearBorn':1985}), 1985);
82 | equals(bornOn({'type':'car','yearBuilt':2000}), 2000);
83 | });
84 |
85 | test("pluck undefined property", function() {
86 | var pluckMM = multimethod('type')
87 | .default(1);
88 | equals(pluckMM({}),1);
89 | });
90 |
91 | test("deep equality example", function() {
92 | var greatPairs = multimethod()
93 | .when( ["Salt", "Pepper"], "Shakers" )
94 | .when( [ { "name": "Bonnie" }, { "name": "Clyde" } ], "Robbers" )
95 | .default( "?" );
96 | equals("?", greatPairs(["MJ", "Pippen"]));
97 | equals("Shakers", greatPairs(["Salt", "Pepper"]));
98 | equals("Robbers", greatPairs([ { "name": "Bonnie" }, { "name": "Clyde" } ]));
99 | });
100 |
101 | test("calling dispatch throws", function() {
102 | try {
103 | var mm = multimethod().dispatch(1);
104 | equals(true, false);
105 | } catch(e) {
106 | equals(true, true);
107 | }
108 | });
109 | });
110 |
--------------------------------------------------------------------------------
/test/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Multimethod Test Suite
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/test/vendor/jquery.js:
--------------------------------------------------------------------------------
1 | /*
2 | * jQuery JavaScript Library v1.3.2
3 | * http://jquery.com/
4 | *
5 | * Copyright (c) 2009 John Resig
6 | * Dual licensed under the MIT and GPL licenses.
7 | * http://docs.jquery.com/License
8 | *
9 | * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
10 | * Revision: 6246
11 | */
12 | (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=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;G1||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-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("",""]||!O.indexOf("",""]||O.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,""]||!O.indexOf(""," "]||(!O.indexOf(""," "]||!O.indexOf(""," "]||!o.support.htmlSerialize&&[1,"div","
"]||[0,"",""];L.innerHTML=Q[1]+S+Q[2];while(Q[0]--){L=L.lastChild}if(!o.support.tbody){var R=/"&&!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;E0?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)})}});
13 | /*
14 | * Sizzle CSS Selector Engine - v0.9.3
15 | * Copyright 2009, The Dojo Foundation
16 | * Released under the MIT, BSD, and GPL Licenses.
17 | * More information: http://sizzlejs.com/
18 | */
19 | (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":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=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 UT[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=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 ";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=" ";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="
";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="
";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;W0){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;Z0||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(Fa text ';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("
").append(M.responseText.replace(/