├── tmp
├── restart.txt
└── .save
├── public
├── tmp
│ └── restart.txt
├── wse.css
├── wse.js
└── jquery-1.4.1.js
├── .gitignore
├── config.ru
├── README
├── views
├── participants.haml
├── register.haml
├── done.haml
├── wse.haml
├── stats.haml
├── index.haml
└── stats_id.haml
├── makewords.rb
├── documents.rb
├── app.rb
├── helpers.rb
├── words.json
└── letters.json
/tmp/restart.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/public/tmp/restart.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tmp/.save:
--------------------------------------------------------------------------------
1 | This is so git will track this folder
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.swo
3 | *.*~
4 | *~
5 | data/*.json
6 |
--------------------------------------------------------------------------------
/config.ru:
--------------------------------------------------------------------------------
1 |
2 | require 'rubygems'
3 | require 'sinatra'
4 | require 'app.rb'
5 |
6 | #root_dir = File.dirname(__FILE__)
7 |
8 | #set :environment, ENV['RACK_ENV'].to_sym
9 | #set :root, root_dir
10 | #set :app_file, File.join(root_dir, 'app.rb')
11 | #disable :run
12 |
13 | run Sinatra::Application
14 |
15 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 |
2 | This is an implementation of the Word Superiority Effect as a Sinatra web
3 | application. It's main purpose is so that I can complete the lab required
4 | for my psychology class, but it has a bonus of allowing me to play with
5 | Sinatra as well.
6 |
7 | For more information on the WSE, see here: http://en.wikipedia.org/wiki/Word_superiority_effect
8 |
9 |
--------------------------------------------------------------------------------
/views/participants.haml:
--------------------------------------------------------------------------------
1 | !!! 5
2 | %head
3 | %title W-S-E
4 | %link{:rel => "stylesheet", :href => "wse.css", :type => "text/css", :charset => "utf-8"}
5 | %body
6 | %h1 Participants
7 | %p="#{parts.size} participants"
8 | %ul
9 | - parts.each do |part|
10 | %li
11 | %a{:href => "/stats/#{part[:_id]}"}="age: #{part[:age]}, gender: #{part[:gender]}, id: #{part[:_id]}"
12 |
13 |
--------------------------------------------------------------------------------
/views/register.haml:
--------------------------------------------------------------------------------
1 | !!! 5
2 | %head
3 | %title W-S-E
4 | %script{:type => "text/javascript", :src => "jquery-1.4.1.js"}
5 | %link{:rel => "stylesheet", :href => "wse.css", :type => "text/css", :charset => "utf-8"}
6 | %body
7 | %form#form{:method => "post", :action => "/register"}
8 | %input#age{:name => "age", :maxlength => "2", :placeholder => "Age"}
9 | %select#gender{:name => "gender"}
10 | %option Male
11 | %option Female
12 | %input{:type => "Submit", :value => "Submit"}
13 |
14 |
--------------------------------------------------------------------------------
/views/done.haml:
--------------------------------------------------------------------------------
1 | !!! 5
2 | %head
3 | %title Thank You
4 | %body
5 | %h1 Thanks for Participating
6 | %p
7 | :markdown
8 | Thank you for your participation, the goal of this was to
9 | investigate whether or not people recognize letters better
10 | in the context of words or on their own. This was done by
11 | showing you either words, letters, or letters disguised as
12 | words, and recording if you recognize what you were seeing.
13 |
14 | Thanks for your help. If you have any more questions feel free
15 | to ask me.
16 | %a{:href => "/stats/#{partID}"}Click here to see your results
17 |
18 |
--------------------------------------------------------------------------------
/views/wse.haml:
--------------------------------------------------------------------------------
1 | !!! 5
2 | %head
3 | %title W-S-E
4 | %script{:type => "text/javascript", :src => "jquery-1.4.1.js"}
5 | %script{:type => "text/javascript", :src => "wse.js"}
6 | %link{:rel => "stylesheet", :href => "wse.css", :type => "text/css", :charset => "utf-8"}
7 | %body
8 | #test-area
9 | %span#test-text
10 | #controls
11 | #other
12 | #start.button
13 | %span#start-message.message-text Click Here To Start
14 | #next.button
15 | %span#next-message.message-text Next
16 | #done.button
17 | %span#done-message.message-text All Done
18 | #buttons
19 | #button-left.button
20 | %span#letter-left.button-text
21 | #button-right.button
22 | %span#letter-right.button-text
23 |
24 |
25 |
--------------------------------------------------------------------------------
/makewords.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require 'rubygems'
4 | require 'json'
5 | require 'documents'
6 |
7 |
8 | WORDS = JSON::parse(File.read("words.json"))
9 | LETTERS = JSON::parse(File.read("letters.json"))
10 |
11 | WORDS.each do |word|
12 | w = Word.new(:type => "word",
13 | :word => word['word'],
14 | :index => word['index'],
15 | :letter => word['letter'])
16 | w.save
17 | end
18 |
19 | LETTERS.each do |word|
20 | l = Word.new(:type => "letter",
21 | :word => word['word'],
22 | :index => word['index'],
23 | :letter => word['letter'])
24 | l.save
25 |
26 | m = Word.new(:type => "masked",
27 | :word => word['word'].gsub(' ', '#'),
28 | :index => word['index'],
29 | :letter => word['letter'])
30 | m.save
31 | end
32 |
33 |
--------------------------------------------------------------------------------
/views/stats.haml:
--------------------------------------------------------------------------------
1 | !!! 5
2 | %head
3 | %title W-S-E
4 | %link{:rel => "stylesheet", :href => "wse.css", :type => "text/css", :charset => "utf-8"}
5 | %body
6 | %h1 Global Stats
7 | %h2="#{num_parts} total participants"
8 | %table
9 | %tr
10 | %th
11 | %th Words
12 | %th Letters
13 | %th Masked
14 | %th Total
15 | %tr
16 | %td Correct
17 | %td=stats[:word][:correct]
18 | %td=stats[:letter][:correct]
19 | %td=stats[:masked][:correct]
20 | %td=stats[:total][:correct]
21 | %tr
22 | %td Completed
23 | %td=stats[:word][:size]
24 | %td=stats[:letter][:size]
25 | %td=stats[:masked][:size]
26 | %td=stats[:total][:size]
27 | %tr
28 | %td Percent
29 | %td=stats[:word][:percent]
30 | %td=stats[:letter][:percent]
31 | %td=stats[:masked][:percent]
32 | %td=stats[:total][:percent]
33 |
34 |
--------------------------------------------------------------------------------
/public/wse.css:
--------------------------------------------------------------------------------
1 | body {
2 | text-align: center;
3 | }
4 |
5 | #test-area {
6 | width:600px;
7 | height:300px;
8 | margin-left:auto;
9 | margin-right:auto;
10 | }
11 |
12 | #test-text {
13 | display:block;
14 | font-family:Helvetica, sans-serif;
15 | font-size:85pt;
16 | padding-top:100px;
17 | margin-bottom:auto;
18 | }
19 |
20 | #controls {
21 | margin:50px;
22 | }
23 |
24 | .button {
25 | display:inline;
26 | border: 3px black solid;
27 | padding: 20px 50px;
28 | padding-top:35px;
29 | margin: 20px 40px;
30 | -webkit-border-radius: 8px;
31 | -moz-border-radius: 8px;
32 | }
33 |
34 | .button:hover {
35 | border-color: blue;
36 | }
37 |
38 | .button:active {
39 | border-color: green;
40 | background-color:green;
41 | }
42 |
43 | .button-text {
44 | padding: 0; margin: 0;
45 | font-family: Helvetica, sans-serif;
46 | font-size: 30pt;
47 | }
48 |
49 | .message-text {
50 | font-family: Helvetica, sans-serif;
51 | font-size: 18pt;
52 | }
53 |
54 | .hide {
55 | display:none;
56 | }
57 |
--------------------------------------------------------------------------------
/documents.rb:
--------------------------------------------------------------------------------
1 | require 'couchrest'
2 |
3 | SERVER = CouchRest.new
4 | DB = SERVER.database!('word-superiority-test-2')
5 |
6 | class Participant < CouchRest::ExtendedDocument
7 | use_database DB
8 |
9 | property :age
10 | property :gender
11 |
12 | timestamps!
13 |
14 | end
15 |
16 | class Word < CouchRest::ExtendedDocument
17 | use_database DB
18 |
19 | property :type
20 | property :word
21 | property :index
22 | property :letter
23 |
24 | view_by :type
25 |
26 | end
27 |
28 | class Choice < CouchRest::ExtendedDocument
29 | use_database DB
30 |
31 | property :word, :cast_as => 'Word'
32 | property :participant, :cast_as => 'Participant'
33 | property :choice
34 |
35 | timestamps!
36 |
37 | view_by :participant,
38 | :map => <<-EOJS
39 | function(doc){
40 | if(doc['couchrest-type'] == 'Choice') {
41 | emit(doc.participant._id, doc);
42 | }
43 | }
44 | EOJS
45 | view_by :participant_and_type,
46 | :map => <<-EOJS
47 | function(doc){
48 | if (doc['couchrest-type'] == 'Choice') {
49 | emit([doc.participant._id, doc.word.type], doc);
50 | }
51 | }
52 | EOJS
53 |
54 | end
55 |
56 |
--------------------------------------------------------------------------------
/views/index.haml:
--------------------------------------------------------------------------------
1 | !!! 5
2 | %head
3 | %title W-S-E
4 | %link{:rel => "stylesheet", :href => "wse.css", :type => "text/css", :charset => "utf-8"}
5 | %body
6 | %h1 Word Superiority Effect
7 | %p
8 | :markdown
9 | This is a replication of a word superiority effect test
10 |
11 | Here's what's going to happen:
12 |
13 | You'll click "Begin" down there at the bottom.
14 |
15 | You'll input your age, and gender, and submit it.
16 |
17 | You will find yourself on a page with a "Start" button.
18 |
19 | When you click the button, a word, letter, or letter disguised as a word will flash briefly.
20 |
21 | It will then be shown again, this time with the letters hidden and a spot indicated.
22 |
23 | 2 more buttons will appear, each with a letter on it.
24 |
25 | You will select the button that matches the letter that should go in the spot that is indicated.
26 |
27 | A "Next" button will appear to take you to a new word.
28 |
29 | After 60 words, you'll be done.
30 |
31 | The test should take about 15 to 20 minutes overall. Make sure
32 | you watch carefully for the word, it flashes _very_ briefly.
33 |
34 | More information about it will be given once the test has
35 | been completed.
36 |
37 | [Begin](/register)
38 |
39 |
--------------------------------------------------------------------------------
/views/stats_id.haml:
--------------------------------------------------------------------------------
1 | !!! 5
2 | %head
3 | %title W-S-E
4 | %link{:rel => "stylesheet", :href => "wse.css", :type => "text/css", :charset => "utf-8"}
5 | %body
6 | %h1="Stats for #{ participant[:_id] }"
7 | %h2="Age: #{ participant[:age]}, Gender: #{ participant[:gender] }"
8 |
9 | %table
10 | %tr
11 | %th
12 | %th Words
13 | %th Letters
14 | %th Masked
15 | %th Total
16 | %tr
17 | %td Correct
18 | %td=stats[:word][:correct]
19 | %td=stats[:letter][:correct]
20 | %td=stats[:masked][:correct]
21 | %td=stats[:total][:correct]
22 | %tr
23 | %td Completed
24 | %td=stats[:word][:size]
25 | %td=stats[:letter][:size]
26 | %td=stats[:masked][:size]
27 | %td=stats[:total][:size]
28 | %tr
29 | %td Percent
30 | %td=stats[:word][:percent]
31 | %td=stats[:letter][:percent]
32 | %td=stats[:masked][:percent]
33 | %td=stats[:total][:percent]
34 |
35 | %h3 Choices
36 | %h4 Words
37 | %table
38 | %tr
39 | %th Word
40 | %th Choice
41 | %th Index
42 | - choices[:word].each do |choice|
43 | %tr
44 | %td=choice.word.word
45 | %td=choice.choice
46 | %td=choice.word.index
47 | %h4 Letters
48 | %table
49 | %tr
50 | %th Word
51 | %th Choice
52 | %th Index
53 | - choices[:letter].each do |choice|
54 | %tr
55 | %td=choice.word.word
56 | %td=choice.choice
57 | %td=choice.word.index
58 | %h4 Masked
59 | %table
60 | %tr
61 | %th Word
62 | %th Choice
63 | %th Index
64 | - choices[:masked].each do |choice|
65 | %tr
66 | %td=choice.word.word
67 | %td=choice.choice
68 | %td=choice.word.index
69 |
70 |
--------------------------------------------------------------------------------
/app.rb:
--------------------------------------------------------------------------------
1 |
2 | require 'rubygems'
3 | require 'sinatra'
4 | require 'documents'
5 | require 'helpers'
6 | require 'haml'
7 | require 'ruby-debug'
8 |
9 |
10 | enable :sessions
11 |
12 | get '/' do
13 | haml :index
14 | end
15 |
16 | get '/random' do
17 | redirect '/register' unless session[:partID]
18 | content_type :json
19 | part = Participant.get(session[:partID])
20 | choices = sort_choices(Choice.by_participant :key => session[:partID])
21 | nextt = next_type(choices)
22 | possible = (Word.by_type :key => nextt).reject do |item|
23 | choices[nextt].include? item
24 | end
25 | return possible[rand(possible.size)].to_json
26 | end
27 |
28 | get '/test' do
29 | redirect '/register' unless session[:partID]
30 | haml :wse
31 | end
32 |
33 | post '/test' do
34 | part = Participant.get(session[:partID])
35 | word = Word.get(params[:word])
36 | done = (Choice.by_participant :key => session[:partID]).size >= 60
37 | c = params[:choice]
38 | choice = Choice.new(:participant => part, :word => word, :choice => c)
39 | choice.save unless done
40 | return
41 | end
42 |
43 | get '/register' do
44 | haml :register
45 | end
46 |
47 | post '/register' do
48 | age = params['age'].to_i
49 | gender = params['gender']
50 | part = Participant.new(:age => age, :gender => gender)
51 | part.save
52 | session[:partID] = part[:_id]
53 | redirect '/test'
54 | end
55 |
56 | get '/stats' do
57 | c = Choice.all
58 | choices = sort_choices(c)
59 | stats = gen_stats choices
60 | numparts = Participant.all.size
61 | haml :stats, :locals => {:stats => stats, :num_parts => numparts}
62 | end
63 |
64 | get '/stats/:id' do |id|
65 | part = Participant.get(id)
66 | c = Choice.by_participant :key => id
67 | choices = sort_choices(c)
68 | stats = gen_stats choices
69 | haml :stats_id, :locals => {:stats => stats, :participant => part, :choices => choices}
70 | end
71 |
72 | get '/participants' do
73 | parts = Participant.all
74 | haml :participants, :locals => {:parts => parts}
75 | end
76 |
77 | get '/done' do
78 | haml :done, :locals => {:partID => session[:partID]}
79 | end
80 |
81 |
--------------------------------------------------------------------------------
/helpers.rb:
--------------------------------------------------------------------------------
1 |
2 | helpers do
3 | def sort_choices choices
4 | word, letter, masked = [],[],[]
5 | choices.each do |choice|
6 | #eval(choice['word']['type']) << choice
7 | case choice.word.type
8 | when "word"
9 | word << choice
10 | when "letter"
11 | letter << choice
12 | when "masked"
13 | masked << choice
14 | end
15 | end
16 | {:word => word, :letter => letter, :masked => masked}
17 | end
18 |
19 | def next_type choices
20 | nextt = choices.collect do |k,v|
21 | {:type => k, :size => v.size}
22 | end.reduce({:type => :word, :size => 0}) do |smallest, v|
23 | r = rand()
24 | if v[:size] < 20 and smallest[:size] < 20
25 | (smallest[:size] < v[:size] and r > 0.35) ? smallest : v
26 | elsif v[:size] < 20
27 | v
28 | else
29 | smallest
30 | end
31 | end[:type]
32 | end
33 |
34 | def is_correct choice
35 | if choice.word.word[choice.word.index-1].chr.upcase == choice.choice.upcase
36 | true
37 | else
38 | false
39 | end
40 | end
41 |
42 | def gen_stats choices
43 | m = choices[:masked]
44 | w = choices[:word]
45 | l = choices[:letter]
46 | total = m.size+w.size+l.size
47 |
48 | corm = m.map{|c|is_correct c}.select{|x| x}.size
49 | corml = m.size
50 | mperc = (corm.to_f/corml.to_f * 100).round
51 |
52 | corw = w.map{|c|is_correct c}.select{|x| x}.size
53 | corwl = w.size
54 | mperw = (corw.to_f/corwl * 100).round
55 |
56 | corl = l.map{|c|is_correct c}.select{|x| x}.size
57 | corll = l.size
58 | mperl = (corl.to_f/corll.to_f * 100).round
59 |
60 | totalc = corl + corm + corw
61 | perc = (totalc.to_f/total.to_f * 100).round
62 | {:total => {:percent => perc, :size => total, :correct => totalc},
63 | :word => {:percent => mperw, :size => corwl, :correct => corw},
64 | :letter => {:percent => mperl, :size => corll, :correct => corl},
65 | :masked => {:percent => mperc, :size => corml, :correct => corm}}
66 | end
67 |
68 | def global_stats stats
69 |
70 | end
71 | end
72 |
73 |
--------------------------------------------------------------------------------
/public/wse.js:
--------------------------------------------------------------------------------
1 |
2 | $(document).ready(function(){
3 | setStuffUp();
4 | });
5 |
6 | var completed;
7 | var word;
8 |
9 | function setStuffUp () {
10 | completed = 0;
11 | $("#buttons").hide();
12 | $("#next").hide();
13 | $("#done").hide();
14 | $("#done").click(function(){window.location.replace("/done");});
15 | $("#button-left").click(function(){doSubmit("#letter-left", word);});
16 | $("#button-right").click(function(){doSubmit("#letter-right", word);});
17 | $("#start").click(function(){start();});
18 | $("#next").click(function(){start();});
19 | }
20 |
21 | function start () {
22 | if (completed < 60)
23 | doTest();
24 | else {
25 | finish();
26 | }
27 | }
28 |
29 | function doTest () {
30 | $("#test-text").html(' ');
31 | $("#start").hide();
32 | $("#next").hide();
33 | getWord(function(w){word = w;runAnimation();});
34 | }
35 |
36 | function getWord (callback) {
37 | $.getJSON("/random",function(data){callback(data);});
38 | }
39 |
40 | function runAnimation () {
41 | $("#test-text").hide();
42 | var w = word.word.toUpperCase();
43 | $("#test-text").html(w);
44 | $("#test-text").show();
45 | setTimeout(function(){$("#test-text").hide();testFinished();}, 10);
46 | }
47 |
48 | function testFinished () {
49 | setChoices(word.letter.toUpperCase(), word.word.charAt(word.index-1).toUpperCase());
50 | setTimeout(function(){maskWord(word);$("#test-text").show();}, 1000);
51 | setTimeout(function(){$("#buttons").fadeIn("fast");}, 1500);
52 | }
53 |
54 | function doSubmit (sel) {
55 | $("#test-text").hide();
56 | $("#buttons").fadeOut("fast", function(){
57 | $.post("/test", {'word':word._id, 'choice':$(sel).html()},
58 | function(){
59 | completed += 1;
60 | $("#next").show();
61 | $("#next").fadeIn("fast");
62 | $("#next").show();
63 | });
64 | });
65 | }
66 |
67 | function finish() {
68 | $("#start").hide();
69 | $("#next").hide();
70 | $("#buttons").fadeOut("fast", function(){
71 | $("#done").show();
72 | });
73 | }
74 |
75 | function setChoices (first, second) {
76 | var x = Math.random();
77 | if (x < 0.5) {
78 | $("#letter-left").html(first);
79 | $("#letter-right").html(second);
80 | } else {
81 | $("#letter-left").html(second);
82 | $("#letter-right").html(first);
83 | }
84 | }
85 |
86 | function maskWord (word) {
87 | var letters = word.word.split('');
88 | for (var i = 0; i < word.word.length; i++) {
89 | if (i+1 == word.index) {
90 | letters[i] = "_";
91 | } else if (word.type == 'letter') {
92 | letters[i] = " ";
93 | } else {
94 | letters[i] = "#";
95 | }
96 | }
97 | $("#test-text").html(letters.join(''));
98 | }
99 |
100 |
101 |
--------------------------------------------------------------------------------
/words.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "id":1,
4 | "word": "pots",
5 | "index": 2,
6 | "letter": "a"
7 | },
8 | {
9 | "id":2,
10 | "word": "face",
11 | "index": 3,
12 | "letter": "t"
13 | },
14 | {
15 | "id":3,
16 | "word": "coin",
17 | "index": 1,
18 | "letter": "j"
19 | },
20 | {
21 | "id":4,
22 | "word": "rage",
23 | "index": 3,
24 | "letter": "t"
25 | },
26 | {
27 | "id":5,
28 | "word": "pall",
29 | "index": 4,
30 | "letter": "e"
31 | },
32 | {
33 | "id":6,
34 | "word": "real",
35 | "index": 4,
36 | "letter": "r"
37 | },
38 | {
39 | "id":7,
40 | "word": "neat",
41 | "index": 3,
42 | "letter": "x"
43 | },
44 | {
45 | "id":8,
46 | "word": "side",
47 | "index": 1,
48 | "letter": "r"
49 | },
50 | {
51 | "id":9,
52 | "word": "snap",
53 | "index": 2,
54 | "letter": "l"
55 | },
56 | {
57 | "id":10,
58 | "word": "zone",
59 | "index": 1,
60 | "letter": "c"
61 | },
62 | {
63 | "id":11,
64 | "word": "sore",
65 | "index": 4,
66 | "letter": "t"
67 | },
68 | {
69 | "id":12,
70 | "word": "foul",
71 | "index": 3,
72 | "letter": "o"
73 | },
74 | {
75 | "id":13,
76 | "word": "boot",
77 | "index": 4,
78 | "letter": "b"
79 | },
80 | {
81 | "id":14,
82 | "word": "code",
83 | "index": 1,
84 | "letter": "m"
85 | },
86 | {
87 | "id":15,
88 | "word": "dish",
89 | "index": 4,
90 | "letter": "k"
91 | },
92 | {
93 | "id":16,
94 | "word": "curl",
95 | "index": 1,
96 | "letter": "h"
97 | },
98 | {
99 | "id":17,
100 | "word": "dole",
101 | "index": 2,
102 | "letter": "a"
103 | },
104 | {
105 | "id":18,
106 | "word": "ease",
107 | "index": 4,
108 | "letter": "t"
109 | },
110 | {
111 | "id":19,
112 | "word": "find",
113 | "index": 2,
114 | "letter": "u"
115 | },
116 | {
117 | "id":20,
118 | "word": "gate",
119 | "index": 3,
120 | "letter": "l"
121 | },
122 | {
123 | "id":21,
124 | "word": "keep",
125 | "index": 3,
126 | "letter": "l"
127 | },
128 | {
129 | "id":22,
130 | "word": "lice",
131 | "index": 2,
132 | "letter": "a"
133 | },
134 | {
135 | "id":23,
136 | "word": "mass",
137 | "index": 2,
138 | "letter": "o"
139 | },
140 | {
141 | "id":24,
142 | "word": "maul",
143 | "index": 3,
144 | "letter": "l"
145 | },
146 | {
147 | "id":25,
148 | "word": "mage",
149 | "index": 3,
150 | "letter": "c"
151 | },
152 | {
153 | "id":26,
154 | "word": "muck",
155 | "index": 1,
156 | "letter": "l"
157 | },
158 | {
159 | "id":27,
160 | "word": "nail",
161 | "index": 1,
162 | "letter": "f"
163 | },
164 | {
165 | "id":28,
166 | "word": "tale",
167 | "index": 2,
168 | "letter": "i"
169 | },
170 | {
171 | "id":29,
172 | "word": "wide",
173 | "index": 2,
174 | "letter": "a"
175 | },
176 | {
177 | "id":30,
178 | "word": "want",
179 | "index": 4,
180 | "letter": "d"
181 | },
182 | {
183 | "id":31,
184 | "word": "body",
185 | "index": 4,
186 | "letter": "e"
187 | },
188 | {
189 | "id":32,
190 | "word": "belt",
191 | "index": 4,
192 | "letter": "l"
193 | },
194 | {
195 | "id":33,
196 | "word": "cart",
197 | "index": 3,
198 | "letter": "s"
199 | },
200 | {
201 | "id":34,
202 | "word": "dial",
203 | "index": 2,
204 | "letter": "e"
205 | },
206 | {
207 | "id":35,
208 | "word": "dump",
209 | "index": 1,
210 | "letter": "b"
211 | },
212 | {
213 | "id":36,
214 | "word": "earn",
215 | "index": 1,
216 | "letter": "y"
217 | },
218 | {
219 | "id":37,
220 | "word": "fame",
221 | "index": 1,
222 | "letter": "s"
223 | },
224 | {
225 | "id":38,
226 | "word": "felt",
227 | "index": 3,
228 | "letter": "e"
229 | },
230 | {
231 | "id":39,
232 | "word": "gift",
233 | "index": 1,
234 | "letter": "l"
235 | },
236 | {
237 | "id":40,
238 | "word": "fold",
239 | "index": 1,
240 | "letter": "t"
241 | },
242 | {
243 | "id":41,
244 | "word": "gull",
245 | "index": 2,
246 | "letter": "a"
247 | },
248 | {
249 | "id":42,
250 | "word": "hock",
251 | "index": 2,
252 | "letter": "a"
253 | },
254 | {
255 | "id":43,
256 | "word": "hang",
257 | "index": 2,
258 | "letter": "u"
259 | },
260 | {
261 | "id":44,
262 | "word": "lain",
263 | "index": 4,
264 | "letter": "d"
265 | },
266 | {
267 | "id":45,
268 | "word": "lick",
269 | "index": 2,
270 | "letter": "u"
271 | },
272 | {
273 | "id":46,
274 | "word": "nose",
275 | "index": 3,
276 | "letter": "t"
277 | },
278 | {
279 | "id":47,
280 | "word": "peel",
281 | "index": 4,
282 | "letter": "p"
283 | },
284 | {
285 | "id":48,
286 | "word": "rise",
287 | "index": 3,
288 | "letter": "l"
289 | },
290 | {
291 | "id":49,
292 | "word": "ruin",
293 | "index": 2,
294 | "letter": "a"
295 | },
296 | {
297 | "id":50,
298 | "word": "scam",
299 | "index": 4,
300 | "letter": "n"
301 | },
302 | {
303 | "id":51,
304 | "word": "seep",
305 | "index": 4,
306 | "letter": "n"
307 | },
308 | {
309 | "id":52,
310 | "word": "sham",
311 | "index": 2,
312 | "letter": "c"
313 | },
314 | {
315 | "id":53,
316 | "word": "slug",
317 | "index": 2,
318 | "letter": "n"
319 | },
320 | {
321 | "id":54,
322 | "word": "slur",
323 | "index": 1,
324 | "letter": "b"
325 | },
326 | {
327 | "id":55,
328 | "word": "snip",
329 | "index": 2,
330 | "letter": "k"
331 | },
332 | {
333 | "id":56,
334 | "word": "sore",
335 | "index": 3,
336 | "letter": "l"
337 | },
338 | {
339 | "id":57,
340 | "word": "shut",
341 | "index": 4,
342 | "letter": "n"
343 | },
344 | {
345 | "id":58,
346 | "word": "sire",
347 | "index": 3,
348 | "letter": "t"
349 | },
350 | {
351 | "id":59,
352 | "word": "tile",
353 | "index": 4,
354 | "letter": "l"
355 | },
356 | {
357 | "id":60,
358 | "word": "wale",
359 | "index": 4,
360 | "letter": "l"
361 | }
362 | ]
363 |
--------------------------------------------------------------------------------
/letters.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "word": " a ",
4 | "id": 1,
5 | "index": 2,
6 | "letter": "c"
7 | },
8 | {
9 | "word": " b",
10 | "id": 2,
11 | "index": 4,
12 | "letter": "d"
13 | },
14 | {
15 | "word": " q",
16 | "id": 3,
17 | "index": 4,
18 | "letter": "r"
19 | },
20 | {
21 | "word": " l ",
22 | "id": 4,
23 | "index": 3,
24 | "letter": "i"
25 | },
26 | {
27 | "word": " z ",
28 | "id": 5,
29 | "index": 3,
30 | "letter": "n"
31 | },
32 | {
33 | "word": " y",
34 | "id": 6,
35 | "index": 4,
36 | "letter": "h"
37 | },
38 | {
39 | "word": " g ",
40 | "id": 7,
41 | "index": 3,
42 | "letter": "k"
43 | },
44 | {
45 | "word": "e ",
46 | "id": 8,
47 | "index": 1,
48 | "letter": "o"
49 | },
50 | {
51 | "word": " b ",
52 | "id": 9,
53 | "index": 3,
54 | "letter": "i"
55 | },
56 | {
57 | "word": " d ",
58 | "id": 10,
59 | "index": 3,
60 | "letter": "b"
61 | },
62 | {
63 | "word": " c ",
64 | "id": 11,
65 | "index": 3,
66 | "letter": "o"
67 | },
68 | {
69 | "word": "w ",
70 | "id": 12,
71 | "index": 1,
72 | "letter": "j"
73 | },
74 | {
75 | "word": " a ",
76 | "id": 13,
77 | "index": 2,
78 | "letter": "p"
79 | },
80 | {
81 | "word": " e ",
82 | "id": 14,
83 | "index": 2,
84 | "letter": "m"
85 | },
86 | {
87 | "word": " x ",
88 | "id": 15,
89 | "index": 3,
90 | "letter": "f"
91 | },
92 | {
93 | "word": " c ",
94 | "id": 16,
95 | "index": 2,
96 | "letter": "p"
97 | },
98 | {
99 | "word": "q ",
100 | "id": 17,
101 | "index": 1,
102 | "letter": "p"
103 | },
104 | {
105 | "word": " h ",
106 | "id": 18,
107 | "index": 3,
108 | "letter": "d"
109 | },
110 | {
111 | "word": "c ",
112 | "id": 19,
113 | "index": 1,
114 | "letter": "t"
115 | },
116 | {
117 | "word": " t ",
118 | "id": 20,
119 | "index": 2,
120 | "letter": "z"
121 | },
122 | {
123 | "word": " e ",
124 | "id": 21,
125 | "index": 2,
126 | "letter": "f"
127 | },
128 | {
129 | "word": " o ",
130 | "id": 22,
131 | "index": 3,
132 | "letter": "y"
133 | },
134 | {
135 | "word": "n ",
136 | "id": 23,
137 | "index": 1,
138 | "letter": "r"
139 | },
140 | {
141 | "word": " a ",
142 | "id": 24,
143 | "index": 2,
144 | "letter": "l"
145 | },
146 | {
147 | "word": " g",
148 | "id": 25,
149 | "index": 4,
150 | "letter": "t"
151 | },
152 | {
153 | "word": " r",
154 | "id": 26,
155 | "index": 4,
156 | "letter": "y"
157 | },
158 | {
159 | "word": " f ",
160 | "id": 27,
161 | "index": 3,
162 | "letter": "k"
163 | },
164 | {
165 | "word": " x ",
166 | "id": 28,
167 | "index": 3,
168 | "letter": "o"
169 | },
170 | {
171 | "word": " p",
172 | "id": 29,
173 | "index": 4,
174 | "letter": "g"
175 | },
176 | {
177 | "word": "e ",
178 | "id": 30,
179 | "index": 1,
180 | "letter": "s"
181 | },
182 | {
183 | "word": " r ",
184 | "id": 31,
185 | "index": 3,
186 | "letter": "m"
187 | },
188 | {
189 | "word": "d ",
190 | "id": 32,
191 | "index": 1,
192 | "letter": "u"
193 | },
194 | {
195 | "word": "l ",
196 | "id": 33,
197 | "index": 1,
198 | "letter": "s"
199 | },
200 | {
201 | "word": "m ",
202 | "id": 34,
203 | "index": 1,
204 | "letter": "v"
205 | },
206 | {
207 | "word": " v ",
208 | "id": 35,
209 | "index": 3,
210 | "letter": "u"
211 | },
212 | {
213 | "word": " c ",
214 | "id": 36,
215 | "index": 2,
216 | "letter": "d"
217 | },
218 | {
219 | "word": "l ",
220 | "id": 37,
221 | "index": 1,
222 | "letter": "f"
223 | },
224 | {
225 | "word": " g",
226 | "id": 38,
227 | "index": 4,
228 | "letter": "e"
229 | },
230 | {
231 | "word": " m ",
232 | "id": 39,
233 | "index": 2,
234 | "letter": "s"
235 | },
236 | {
237 | "word": " q ",
238 | "id": 40,
239 | "index": 3,
240 | "letter": "t"
241 | },
242 | {
243 | "word": " g",
244 | "id": 41,
245 | "index": 4,
246 | "letter": "k"
247 | },
248 | {
249 | "word": " n",
250 | "id": 42,
251 | "index": 4,
252 | "letter": "y"
253 | },
254 | {
255 | "word": " j ",
256 | "id": 43,
257 | "index": 2,
258 | "letter": "k"
259 | },
260 | {
261 | "word": " s",
262 | "id": 44,
263 | "index": 4,
264 | "letter": "d"
265 | },
266 | {
267 | "word": " v ",
268 | "id": 45,
269 | "index": 3,
270 | "letter": "b"
271 | },
272 | {
273 | "word": " e ",
274 | "id": 46,
275 | "index": 3,
276 | "letter": "p"
277 | },
278 | {
279 | "word": " i ",
280 | "id": 47,
281 | "index": 2,
282 | "letter": "e"
283 | },
284 | {
285 | "word": " e",
286 | "id": 48,
287 | "index": 4,
288 | "letter": "g"
289 | },
290 | {
291 | "word": " g ",
292 | "id": 49,
293 | "index": 3,
294 | "letter": "l"
295 | },
296 | {
297 | "word": " q ",
298 | "id": 50,
299 | "index": 2,
300 | "letter": "u"
301 | },
302 | {
303 | "word": " s ",
304 | "id": 51,
305 | "index": 3,
306 | "letter": "x"
307 | },
308 | {
309 | "word": "x ",
310 | "id": 52,
311 | "index": 1,
312 | "letter": "i"
313 | },
314 | {
315 | "word": " b ",
316 | "id": 53,
317 | "index": 3,
318 | "letter": "g"
319 | },
320 | {
321 | "word": " n ",
322 | "id": 54,
323 | "index": 3,
324 | "letter": "v"
325 | },
326 | {
327 | "word": "i ",
328 | "id": 55,
329 | "index": 1,
330 | "letter": "a"
331 | },
332 | {
333 | "word": " l ",
334 | "id": 56,
335 | "index": 2,
336 | "letter": "v"
337 | },
338 | {
339 | "word": " d ",
340 | "id": 57,
341 | "index": 2,
342 | "letter": "h"
343 | },
344 | {
345 | "word": " d ",
346 | "id": 58,
347 | "index": 3,
348 | "letter": "v"
349 | },
350 | {
351 | "word": "z ",
352 | "id": 59,
353 | "index": 1,
354 | "letter": "q"
355 | },
356 | {
357 | "word": "h ",
358 | "id": 60,
359 | "index": 1,
360 | "letter": "u"
361 | }
362 | ]
--------------------------------------------------------------------------------
/public/jquery-1.4.1.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery JavaScript Library v1.4.1
3 | * http://jquery.com/
4 | *
5 | * Copyright 2010, John Resig
6 | * Dual licensed under the MIT or GPL Version 2 licenses.
7 | * http://jquery.org/license
8 | *
9 | * Includes Sizzle.js
10 | * http://sizzlejs.com/
11 | * Copyright 2010, The Dojo Foundation
12 | * Released under the MIT, BSD, and GPL Licenses.
13 | *
14 | * Date: Mon Jan 25 19:43:33 2010 -0500
15 | */
16 | (function( window, undefined ) {
17 |
18 | // Define a local copy of jQuery
19 | var jQuery = function( selector, context ) {
20 | // The jQuery object is actually just the init constructor 'enhanced'
21 | return new jQuery.fn.init( selector, context );
22 | },
23 |
24 | // Map over jQuery in case of overwrite
25 | _jQuery = window.jQuery,
26 |
27 | // Map over the $ in case of overwrite
28 | _$ = window.$,
29 |
30 | // Use the correct document accordingly with window argument (sandbox)
31 | document = window.document,
32 |
33 | // A central reference to the root jQuery(document)
34 | rootjQuery,
35 |
36 | // A simple way to check for HTML strings or ID strings
37 | // (both of which we optimize for)
38 | quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/,
39 |
40 | // Is it a simple selector
41 | isSimple = /^.[^:#\[\.,]*$/,
42 |
43 | // Check if a string has a non-whitespace character in it
44 | rnotwhite = /\S/,
45 |
46 | // Used for trimming whitespace
47 | rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g,
48 |
49 | // Match a standalone tag
50 | rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/,
51 |
52 | // Keep a UserAgent string for use with jQuery.browser
53 | userAgent = navigator.userAgent,
54 |
55 | // For matching the engine and version of the browser
56 | browserMatch,
57 |
58 | // Has the ready events already been bound?
59 | readyBound = false,
60 |
61 | // The functions to execute on DOM ready
62 | readyList = [],
63 |
64 | // The ready event handler
65 | DOMContentLoaded,
66 |
67 | // Save a reference to some core methods
68 | toString = Object.prototype.toString,
69 | hasOwnProperty = Object.prototype.hasOwnProperty,
70 | push = Array.prototype.push,
71 | slice = Array.prototype.slice,
72 | indexOf = Array.prototype.indexOf;
73 |
74 | jQuery.fn = jQuery.prototype = {
75 | init: function( selector, context ) {
76 | var match, elem, ret, doc;
77 |
78 | // Handle $(""), $(null), or $(undefined)
79 | if ( !selector ) {
80 | return this;
81 | }
82 |
83 | // Handle $(DOMElement)
84 | if ( selector.nodeType ) {
85 | this.context = this[0] = selector;
86 | this.length = 1;
87 | return this;
88 | }
89 |
90 | // Handle HTML strings
91 | if ( typeof selector === "string" ) {
92 | // Are we dealing with HTML string or an ID?
93 | match = quickExpr.exec( selector );
94 |
95 | // Verify a match, and that no context was specified for #id
96 | if ( match && (match[1] || !context) ) {
97 |
98 | // HANDLE: $(html) -> $(array)
99 | if ( match[1] ) {
100 | doc = (context ? context.ownerDocument || context : document);
101 |
102 | // If a single string is passed in and it's a single tag
103 | // just do a createElement and skip the rest
104 | ret = rsingleTag.exec( selector );
105 |
106 | if ( ret ) {
107 | if ( jQuery.isPlainObject( context ) ) {
108 | selector = [ document.createElement( ret[1] ) ];
109 | jQuery.fn.attr.call( selector, context, true );
110 |
111 | } else {
112 | selector = [ doc.createElement( ret[1] ) ];
113 | }
114 |
115 | } else {
116 | ret = buildFragment( [ match[1] ], [ doc ] );
117 | selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes;
118 | }
119 |
120 | // HANDLE: $("#id")
121 | } else {
122 | elem = document.getElementById( match[2] );
123 |
124 | if ( elem ) {
125 | // Handle the case where IE and Opera return items
126 | // by name instead of ID
127 | if ( elem.id !== match[2] ) {
128 | return rootjQuery.find( selector );
129 | }
130 |
131 | // Otherwise, we inject the element directly into the jQuery object
132 | this.length = 1;
133 | this[0] = elem;
134 | }
135 |
136 | this.context = document;
137 | this.selector = selector;
138 | return this;
139 | }
140 |
141 | // HANDLE: $("TAG")
142 | } else if ( !context && /^\w+$/.test( selector ) ) {
143 | this.selector = selector;
144 | this.context = document;
145 | selector = document.getElementsByTagName( selector );
146 |
147 | // HANDLE: $(expr, $(...))
148 | } else if ( !context || context.jquery ) {
149 | return (context || rootjQuery).find( selector );
150 |
151 | // HANDLE: $(expr, context)
152 | // (which is just equivalent to: $(context).find(expr)
153 | } else {
154 | return jQuery( context ).find( selector );
155 | }
156 |
157 | // HANDLE: $(function)
158 | // Shortcut for document ready
159 | } else if ( jQuery.isFunction( selector ) ) {
160 | return rootjQuery.ready( selector );
161 | }
162 |
163 | if (selector.selector !== undefined) {
164 | this.selector = selector.selector;
165 | this.context = selector.context;
166 | }
167 |
168 | return jQuery.isArray( selector ) ?
169 | this.setArray( selector ) :
170 | jQuery.makeArray( selector, this );
171 | },
172 |
173 | // Start with an empty selector
174 | selector: "",
175 |
176 | // The current version of jQuery being used
177 | jquery: "1.4.1",
178 |
179 | // The default length of a jQuery object is 0
180 | length: 0,
181 |
182 | // The number of elements contained in the matched element set
183 | size: function() {
184 | return this.length;
185 | },
186 |
187 | toArray: function() {
188 | return slice.call( this, 0 );
189 | },
190 |
191 | // Get the Nth element in the matched element set OR
192 | // Get the whole matched element set as a clean array
193 | get: function( num ) {
194 | return num == null ?
195 |
196 | // Return a 'clean' array
197 | this.toArray() :
198 |
199 | // Return just the object
200 | ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] );
201 | },
202 |
203 | // Take an array of elements and push it onto the stack
204 | // (returning the new matched element set)
205 | pushStack: function( elems, name, selector ) {
206 | // Build a new jQuery matched element set
207 | var ret = jQuery( elems || null );
208 |
209 | // Add the old object onto the stack (as a reference)
210 | ret.prevObject = this;
211 |
212 | ret.context = this.context;
213 |
214 | if ( name === "find" ) {
215 | ret.selector = this.selector + (this.selector ? " " : "") + selector;
216 | } else if ( name ) {
217 | ret.selector = this.selector + "." + name + "(" + selector + ")";
218 | }
219 |
220 | // Return the newly-formed element set
221 | return ret;
222 | },
223 |
224 | // Force the current matched set of elements to become
225 | // the specified array of elements (destroying the stack in the process)
226 | // You should use pushStack() in order to do this, but maintain the stack
227 | setArray: function( elems ) {
228 | // Resetting the length to 0, then using the native Array push
229 | // is a super-fast way to populate an object with array-like properties
230 | this.length = 0;
231 | push.apply( this, elems );
232 |
233 | return this;
234 | },
235 |
236 | // Execute a callback for every element in the matched set.
237 | // (You can seed the arguments with an array of args, but this is
238 | // only used internally.)
239 | each: function( callback, args ) {
240 | return jQuery.each( this, callback, args );
241 | },
242 |
243 | ready: function( fn ) {
244 | // Attach the listeners
245 | jQuery.bindReady();
246 |
247 | // If the DOM is already ready
248 | if ( jQuery.isReady ) {
249 | // Execute the function immediately
250 | fn.call( document, jQuery );
251 |
252 | // Otherwise, remember the function for later
253 | } else if ( readyList ) {
254 | // Add the function to the wait list
255 | readyList.push( fn );
256 | }
257 |
258 | return this;
259 | },
260 |
261 | eq: function( i ) {
262 | return i === -1 ?
263 | this.slice( i ) :
264 | this.slice( i, +i + 1 );
265 | },
266 |
267 | first: function() {
268 | return this.eq( 0 );
269 | },
270 |
271 | last: function() {
272 | return this.eq( -1 );
273 | },
274 |
275 | slice: function() {
276 | return this.pushStack( slice.apply( this, arguments ),
277 | "slice", slice.call(arguments).join(",") );
278 | },
279 |
280 | map: function( callback ) {
281 | return this.pushStack( jQuery.map(this, function( elem, i ) {
282 | return callback.call( elem, i, elem );
283 | }));
284 | },
285 |
286 | end: function() {
287 | return this.prevObject || jQuery(null);
288 | },
289 |
290 | // For internal use only.
291 | // Behaves like an Array's method, not like a jQuery method.
292 | push: push,
293 | sort: [].sort,
294 | splice: [].splice
295 | };
296 |
297 | // Give the init function the jQuery prototype for later instantiation
298 | jQuery.fn.init.prototype = jQuery.fn;
299 |
300 | jQuery.extend = jQuery.fn.extend = function() {
301 | // copy reference to target object
302 | var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy;
303 |
304 | // Handle a deep copy situation
305 | if ( typeof target === "boolean" ) {
306 | deep = target;
307 | target = arguments[1] || {};
308 | // skip the boolean and the target
309 | i = 2;
310 | }
311 |
312 | // Handle case when target is a string or something (possible in deep copy)
313 | if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
314 | target = {};
315 | }
316 |
317 | // extend jQuery itself if only one argument is passed
318 | if ( length === i ) {
319 | target = this;
320 | --i;
321 | }
322 |
323 | for ( ; i < length; i++ ) {
324 | // Only deal with non-null/undefined values
325 | if ( (options = arguments[ i ]) != null ) {
326 | // Extend the base object
327 | for ( name in options ) {
328 | src = target[ name ];
329 | copy = options[ name ];
330 |
331 | // Prevent never-ending loop
332 | if ( target === copy ) {
333 | continue;
334 | }
335 |
336 | // Recurse if we're merging object literal values or arrays
337 | if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) {
338 | var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src
339 | : jQuery.isArray(copy) ? [] : {};
340 |
341 | // Never move original objects, clone them
342 | target[ name ] = jQuery.extend( deep, clone, copy );
343 |
344 | // Don't bring in undefined values
345 | } else if ( copy !== undefined ) {
346 | target[ name ] = copy;
347 | }
348 | }
349 | }
350 | }
351 |
352 | // Return the modified object
353 | return target;
354 | };
355 |
356 | jQuery.extend({
357 | noConflict: function( deep ) {
358 | window.$ = _$;
359 |
360 | if ( deep ) {
361 | window.jQuery = _jQuery;
362 | }
363 |
364 | return jQuery;
365 | },
366 |
367 | // Is the DOM ready to be used? Set to true once it occurs.
368 | isReady: false,
369 |
370 | // Handle when the DOM is ready
371 | ready: function() {
372 | // Make sure that the DOM is not already loaded
373 | if ( !jQuery.isReady ) {
374 | // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
375 | if ( !document.body ) {
376 | return setTimeout( jQuery.ready, 13 );
377 | }
378 |
379 | // Remember that the DOM is ready
380 | jQuery.isReady = true;
381 |
382 | // If there are functions bound, to execute
383 | if ( readyList ) {
384 | // Execute all of them
385 | var fn, i = 0;
386 | while ( (fn = readyList[ i++ ]) ) {
387 | fn.call( document, jQuery );
388 | }
389 |
390 | // Reset the list of functions
391 | readyList = null;
392 | }
393 |
394 | // Trigger any bound ready events
395 | if ( jQuery.fn.triggerHandler ) {
396 | jQuery( document ).triggerHandler( "ready" );
397 | }
398 | }
399 | },
400 |
401 | bindReady: function() {
402 | if ( readyBound ) {
403 | return;
404 | }
405 |
406 | readyBound = true;
407 |
408 | // Catch cases where $(document).ready() is called after the
409 | // browser event has already occurred.
410 | if ( document.readyState === "complete" ) {
411 | return jQuery.ready();
412 | }
413 |
414 | // Mozilla, Opera and webkit nightlies currently support this event
415 | if ( document.addEventListener ) {
416 | // Use the handy event callback
417 | document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );
418 |
419 | // A fallback to window.onload, that will always work
420 | window.addEventListener( "load", jQuery.ready, false );
421 |
422 | // If IE event model is used
423 | } else if ( document.attachEvent ) {
424 | // ensure firing before onload,
425 | // maybe late but safe also for iframes
426 | document.attachEvent("onreadystatechange", DOMContentLoaded);
427 |
428 | // A fallback to window.onload, that will always work
429 | window.attachEvent( "onload", jQuery.ready );
430 |
431 | // If IE and not a frame
432 | // continually check to see if the document is ready
433 | var toplevel = false;
434 |
435 | try {
436 | toplevel = window.frameElement == null;
437 | } catch(e) {}
438 |
439 | if ( document.documentElement.doScroll && toplevel ) {
440 | doScrollCheck();
441 | }
442 | }
443 | },
444 |
445 | // See test/unit/core.js for details concerning isFunction.
446 | // Since version 1.3, DOM methods and functions like alert
447 | // aren't supported. They return false on IE (#2968).
448 | isFunction: function( obj ) {
449 | return toString.call(obj) === "[object Function]";
450 | },
451 |
452 | isArray: function( obj ) {
453 | return toString.call(obj) === "[object Array]";
454 | },
455 |
456 | isPlainObject: function( obj ) {
457 | // Must be an Object.
458 | // Because of IE, we also have to check the presence of the constructor property.
459 | // Make sure that DOM nodes and window objects don't pass through, as well
460 | if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
461 | return false;
462 | }
463 |
464 | // Not own constructor property must be Object
465 | if ( obj.constructor
466 | && !hasOwnProperty.call(obj, "constructor")
467 | && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
468 | return false;
469 | }
470 |
471 | // Own properties are enumerated firstly, so to speed up,
472 | // if last one is own, then all properties are own.
473 |
474 | var key;
475 | for ( key in obj ) {}
476 |
477 | return key === undefined || hasOwnProperty.call( obj, key );
478 | },
479 |
480 | isEmptyObject: function( obj ) {
481 | for ( var name in obj ) {
482 | return false;
483 | }
484 | return true;
485 | },
486 |
487 | error: function( msg ) {
488 | throw msg;
489 | },
490 |
491 | parseJSON: function( data ) {
492 | if ( typeof data !== "string" || !data ) {
493 | return null;
494 | }
495 |
496 | // Make sure the incoming data is actual JSON
497 | // Logic borrowed from http://json.org/json2.js
498 | if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@")
499 | .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]")
500 | .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) {
501 |
502 | // Try to use the native JSON parser first
503 | return window.JSON && window.JSON.parse ?
504 | window.JSON.parse( data ) :
505 | (new Function("return " + data))();
506 |
507 | } else {
508 | jQuery.error( "Invalid JSON: " + data );
509 | }
510 | },
511 |
512 | noop: function() {},
513 |
514 | // Evalulates a script in a global context
515 | globalEval: function( data ) {
516 | if ( data && rnotwhite.test(data) ) {
517 | // Inspired by code by Andrea Giammarchi
518 | // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html
519 | var head = document.getElementsByTagName("head")[0] || document.documentElement,
520 | script = document.createElement("script");
521 |
522 | script.type = "text/javascript";
523 |
524 | if ( jQuery.support.scriptEval ) {
525 | script.appendChild( document.createTextNode( data ) );
526 | } else {
527 | script.text = data;
528 | }
529 |
530 | // Use insertBefore instead of appendChild to circumvent an IE6 bug.
531 | // This arises when a base node is used (#2709).
532 | head.insertBefore( script, head.firstChild );
533 | head.removeChild( script );
534 | }
535 | },
536 |
537 | nodeName: function( elem, name ) {
538 | return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();
539 | },
540 |
541 | // args is for internal usage only
542 | each: function( object, callback, args ) {
543 | var name, i = 0,
544 | length = object.length,
545 | isObj = length === undefined || jQuery.isFunction(object);
546 |
547 | if ( args ) {
548 | if ( isObj ) {
549 | for ( name in object ) {
550 | if ( callback.apply( object[ name ], args ) === false ) {
551 | break;
552 | }
553 | }
554 | } else {
555 | for ( ; i < length; ) {
556 | if ( callback.apply( object[ i++ ], args ) === false ) {
557 | break;
558 | }
559 | }
560 | }
561 |
562 | // A special, fast, case for the most common use of each
563 | } else {
564 | if ( isObj ) {
565 | for ( name in object ) {
566 | if ( callback.call( object[ name ], name, object[ name ] ) === false ) {
567 | break;
568 | }
569 | }
570 | } else {
571 | for ( var value = object[0];
572 | i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}
573 | }
574 | }
575 |
576 | return object;
577 | },
578 |
579 | trim: function( text ) {
580 | return (text || "").replace( rtrim, "" );
581 | },
582 |
583 | // results is for internal usage only
584 | makeArray: function( array, results ) {
585 | var ret = results || [];
586 |
587 | if ( array != null ) {
588 | // The window, strings (and functions) also have 'length'
589 | // The extra typeof function check is to prevent crashes
590 | // in Safari 2 (See: #3039)
591 | if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) {
592 | push.call( ret, array );
593 | } else {
594 | jQuery.merge( ret, array );
595 | }
596 | }
597 |
598 | return ret;
599 | },
600 |
601 | inArray: function( elem, array ) {
602 | if ( array.indexOf ) {
603 | return array.indexOf( elem );
604 | }
605 |
606 | for ( var i = 0, length = array.length; i < length; i++ ) {
607 | if ( array[ i ] === elem ) {
608 | return i;
609 | }
610 | }
611 |
612 | return -1;
613 | },
614 |
615 | merge: function( first, second ) {
616 | var i = first.length, j = 0;
617 |
618 | if ( typeof second.length === "number" ) {
619 | for ( var l = second.length; j < l; j++ ) {
620 | first[ i++ ] = second[ j ];
621 | }
622 | } else {
623 | while ( second[j] !== undefined ) {
624 | first[ i++ ] = second[ j++ ];
625 | }
626 | }
627 |
628 | first.length = i;
629 |
630 | return first;
631 | },
632 |
633 | grep: function( elems, callback, inv ) {
634 | var ret = [];
635 |
636 | // Go through the array, only saving the items
637 | // that pass the validator function
638 | for ( var i = 0, length = elems.length; i < length; i++ ) {
639 | if ( !inv !== !callback( elems[ i ], i ) ) {
640 | ret.push( elems[ i ] );
641 | }
642 | }
643 |
644 | return ret;
645 | },
646 |
647 | // arg is for internal usage only
648 | map: function( elems, callback, arg ) {
649 | var ret = [], value;
650 |
651 | // Go through the array, translating each of the items to their
652 | // new value (or values).
653 | for ( var i = 0, length = elems.length; i < length; i++ ) {
654 | value = callback( elems[ i ], i, arg );
655 |
656 | if ( value != null ) {
657 | ret[ ret.length ] = value;
658 | }
659 | }
660 |
661 | return ret.concat.apply( [], ret );
662 | },
663 |
664 | // A global GUID counter for objects
665 | guid: 1,
666 |
667 | proxy: function( fn, proxy, thisObject ) {
668 | if ( arguments.length === 2 ) {
669 | if ( typeof proxy === "string" ) {
670 | thisObject = fn;
671 | fn = thisObject[ proxy ];
672 | proxy = undefined;
673 |
674 | } else if ( proxy && !jQuery.isFunction( proxy ) ) {
675 | thisObject = proxy;
676 | proxy = undefined;
677 | }
678 | }
679 |
680 | if ( !proxy && fn ) {
681 | proxy = function() {
682 | return fn.apply( thisObject || this, arguments );
683 | };
684 | }
685 |
686 | // Set the guid of unique handler to the same of original handler, so it can be removed
687 | if ( fn ) {
688 | proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;
689 | }
690 |
691 | // So proxy can be declared as an argument
692 | return proxy;
693 | },
694 |
695 | // Use of jQuery.browser is frowned upon.
696 | // More details: http://docs.jquery.com/Utilities/jQuery.browser
697 | uaMatch: function( ua ) {
698 | ua = ua.toLowerCase();
699 |
700 | var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
701 | /(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) ||
702 | /(msie) ([\w.]+)/.exec( ua ) ||
703 | !/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) ||
704 | [];
705 |
706 | return { browser: match[1] || "", version: match[2] || "0" };
707 | },
708 |
709 | browser: {}
710 | });
711 |
712 | browserMatch = jQuery.uaMatch( userAgent );
713 | if ( browserMatch.browser ) {
714 | jQuery.browser[ browserMatch.browser ] = true;
715 | jQuery.browser.version = browserMatch.version;
716 | }
717 |
718 | // Deprecated, use jQuery.browser.webkit instead
719 | if ( jQuery.browser.webkit ) {
720 | jQuery.browser.safari = true;
721 | }
722 |
723 | if ( indexOf ) {
724 | jQuery.inArray = function( elem, array ) {
725 | return indexOf.call( array, elem );
726 | };
727 | }
728 |
729 | // All jQuery objects should point back to these
730 | rootjQuery = jQuery(document);
731 |
732 | // Cleanup functions for the document ready method
733 | if ( document.addEventListener ) {
734 | DOMContentLoaded = function() {
735 | document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false );
736 | jQuery.ready();
737 | };
738 |
739 | } else if ( document.attachEvent ) {
740 | DOMContentLoaded = function() {
741 | // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
742 | if ( document.readyState === "complete" ) {
743 | document.detachEvent( "onreadystatechange", DOMContentLoaded );
744 | jQuery.ready();
745 | }
746 | };
747 | }
748 |
749 | // The DOM ready check for Internet Explorer
750 | function doScrollCheck() {
751 | if ( jQuery.isReady ) {
752 | return;
753 | }
754 |
755 | try {
756 | // If IE is used, use the trick by Diego Perini
757 | // http://javascript.nwbox.com/IEContentLoaded/
758 | document.documentElement.doScroll("left");
759 | } catch( error ) {
760 | setTimeout( doScrollCheck, 1 );
761 | return;
762 | }
763 |
764 | // and execute any waiting functions
765 | jQuery.ready();
766 | }
767 |
768 | function evalScript( i, elem ) {
769 | if ( elem.src ) {
770 | jQuery.ajax({
771 | url: elem.src,
772 | async: false,
773 | dataType: "script"
774 | });
775 | } else {
776 | jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" );
777 | }
778 |
779 | if ( elem.parentNode ) {
780 | elem.parentNode.removeChild( elem );
781 | }
782 | }
783 |
784 | // Mutifunctional method to get and set values to a collection
785 | // The value/s can be optionally by executed if its a function
786 | function access( elems, key, value, exec, fn, pass ) {
787 | var length = elems.length;
788 |
789 | // Setting many attributes
790 | if ( typeof key === "object" ) {
791 | for ( var k in key ) {
792 | access( elems, k, key[k], exec, fn, value );
793 | }
794 | return elems;
795 | }
796 |
797 | // Setting one attribute
798 | if ( value !== undefined ) {
799 | // Optionally, function values get executed if exec is true
800 | exec = !pass && exec && jQuery.isFunction(value);
801 |
802 | for ( var i = 0; i < length; i++ ) {
803 | fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );
804 | }
805 |
806 | return elems;
807 | }
808 |
809 | // Getting an attribute
810 | return length ? fn( elems[0], key ) : null;
811 | }
812 |
813 | function now() {
814 | return (new Date).getTime();
815 | }
816 | (function() {
817 |
818 | jQuery.support = {};
819 |
820 | var root = document.documentElement,
821 | script = document.createElement("script"),
822 | div = document.createElement("div"),
823 | id = "script" + now();
824 |
825 | div.style.display = "none";
826 | div.innerHTML = "
a";
827 |
828 | var all = div.getElementsByTagName("*"),
829 | a = div.getElementsByTagName("a")[0];
830 |
831 | // Can't get basic test support
832 | if ( !all || !all.length || !a ) {
833 | return;
834 | }
835 |
836 | jQuery.support = {
837 | // IE strips leading whitespace when .innerHTML is used
838 | leadingWhitespace: div.firstChild.nodeType === 3,
839 |
840 | // Make sure that tbody elements aren't automatically inserted
841 | // IE will insert them into empty tables
842 | tbody: !div.getElementsByTagName("tbody").length,
843 |
844 | // Make sure that link elements get serialized correctly by innerHTML
845 | // This requires a wrapper element in IE
846 | htmlSerialize: !!div.getElementsByTagName("link").length,
847 |
848 | // Get the style information from getAttribute
849 | // (IE uses .cssText insted)
850 | style: /red/.test( a.getAttribute("style") ),
851 |
852 | // Make sure that URLs aren't manipulated
853 | // (IE normalizes it by default)
854 | hrefNormalized: a.getAttribute("href") === "/a",
855 |
856 | // Make sure that element opacity exists
857 | // (IE uses filter instead)
858 | // Use a regex to work around a WebKit issue. See #5145
859 | opacity: /^0.55$/.test( a.style.opacity ),
860 |
861 | // Verify style float existence
862 | // (IE uses styleFloat instead of cssFloat)
863 | cssFloat: !!a.style.cssFloat,
864 |
865 | // Make sure that if no value is specified for a checkbox
866 | // that it defaults to "on".
867 | // (WebKit defaults to "" instead)
868 | checkOn: div.getElementsByTagName("input")[0].value === "on",
869 |
870 | // Make sure that a selected-by-default option has a working selected property.
871 | // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)
872 | optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected,
873 |
874 | // Will be defined later
875 | checkClone: false,
876 | scriptEval: false,
877 | noCloneEvent: true,
878 | boxModel: null
879 | };
880 |
881 | script.type = "text/javascript";
882 | try {
883 | script.appendChild( document.createTextNode( "window." + id + "=1;" ) );
884 | } catch(e) {}
885 |
886 | root.insertBefore( script, root.firstChild );
887 |
888 | // Make sure that the execution of code works by injecting a script
889 | // tag with appendChild/createTextNode
890 | // (IE doesn't support this, fails, and uses .text instead)
891 | if ( window[ id ] ) {
892 | jQuery.support.scriptEval = true;
893 | delete window[ id ];
894 | }
895 |
896 | root.removeChild( script );
897 |
898 | if ( div.attachEvent && div.fireEvent ) {
899 | div.attachEvent("onclick", function click() {
900 | // Cloning a node shouldn't copy over any
901 | // bound event handlers (IE does this)
902 | jQuery.support.noCloneEvent = false;
903 | div.detachEvent("onclick", click);
904 | });
905 | div.cloneNode(true).fireEvent("onclick");
906 | }
907 |
908 | div = document.createElement("div");
909 | div.innerHTML = "";
910 |
911 | var fragment = document.createDocumentFragment();
912 | fragment.appendChild( div.firstChild );
913 |
914 | // WebKit doesn't clone checked state correctly in fragments
915 | jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;
916 |
917 | // Figure out if the W3C box model works as expected
918 | // document.body must exist before we can do this
919 | jQuery(function() {
920 | var div = document.createElement("div");
921 | div.style.width = div.style.paddingLeft = "1px";
922 |
923 | document.body.appendChild( div );
924 | jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;
925 | document.body.removeChild( div ).style.display = 'none';
926 | div = null;
927 | });
928 |
929 | // Technique from Juriy Zaytsev
930 | // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
931 | var eventSupported = function( eventName ) {
932 | var el = document.createElement("div");
933 | eventName = "on" + eventName;
934 |
935 | var isSupported = (eventName in el);
936 | if ( !isSupported ) {
937 | el.setAttribute(eventName, "return;");
938 | isSupported = typeof el[eventName] === "function";
939 | }
940 | el = null;
941 |
942 | return isSupported;
943 | };
944 |
945 | jQuery.support.submitBubbles = eventSupported("submit");
946 | jQuery.support.changeBubbles = eventSupported("change");
947 |
948 | // release memory in IE
949 | root = script = div = all = a = null;
950 | })();
951 |
952 | jQuery.props = {
953 | "for": "htmlFor",
954 | "class": "className",
955 | readonly: "readOnly",
956 | maxlength: "maxLength",
957 | cellspacing: "cellSpacing",
958 | rowspan: "rowSpan",
959 | colspan: "colSpan",
960 | tabindex: "tabIndex",
961 | usemap: "useMap",
962 | frameborder: "frameBorder"
963 | };
964 | var expando = "jQuery" + now(), uuid = 0, windowData = {};
965 | var emptyObject = {};
966 |
967 | jQuery.extend({
968 | cache: {},
969 |
970 | expando:expando,
971 |
972 | // The following elements throw uncatchable exceptions if you
973 | // attempt to add expando properties to them.
974 | noData: {
975 | "embed": true,
976 | "object": true,
977 | "applet": true
978 | },
979 |
980 | data: function( elem, name, data ) {
981 | if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
982 | return;
983 | }
984 |
985 | elem = elem == window ?
986 | windowData :
987 | elem;
988 |
989 | var id = elem[ expando ], cache = jQuery.cache, thisCache;
990 |
991 | // Handle the case where there's no name immediately
992 | if ( !name && !id ) {
993 | return null;
994 | }
995 |
996 | // Compute a unique ID for the element
997 | if ( !id ) {
998 | id = ++uuid;
999 | }
1000 |
1001 | // Avoid generating a new cache unless none exists and we
1002 | // want to manipulate it.
1003 | if ( typeof name === "object" ) {
1004 | elem[ expando ] = id;
1005 | thisCache = cache[ id ] = jQuery.extend(true, {}, name);
1006 | } else if ( cache[ id ] ) {
1007 | thisCache = cache[ id ];
1008 | } else if ( typeof data === "undefined" ) {
1009 | thisCache = emptyObject;
1010 | } else {
1011 | thisCache = cache[ id ] = {};
1012 | }
1013 |
1014 | // Prevent overriding the named cache with undefined values
1015 | if ( data !== undefined ) {
1016 | elem[ expando ] = id;
1017 | thisCache[ name ] = data;
1018 | }
1019 |
1020 | return typeof name === "string" ? thisCache[ name ] : thisCache;
1021 | },
1022 |
1023 | removeData: function( elem, name ) {
1024 | if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {
1025 | return;
1026 | }
1027 |
1028 | elem = elem == window ?
1029 | windowData :
1030 | elem;
1031 |
1032 | var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ];
1033 |
1034 | // If we want to remove a specific section of the element's data
1035 | if ( name ) {
1036 | if ( thisCache ) {
1037 | // Remove the section of cache data
1038 | delete thisCache[ name ];
1039 |
1040 | // If we've removed all the data, remove the element's cache
1041 | if ( jQuery.isEmptyObject(thisCache) ) {
1042 | jQuery.removeData( elem );
1043 | }
1044 | }
1045 |
1046 | // Otherwise, we want to remove all of the element's data
1047 | } else {
1048 | // Clean up the element expando
1049 | try {
1050 | delete elem[ expando ];
1051 | } catch( e ) {
1052 | // IE has trouble directly removing the expando
1053 | // but it's ok with using removeAttribute
1054 | if ( elem.removeAttribute ) {
1055 | elem.removeAttribute( expando );
1056 | }
1057 | }
1058 |
1059 | // Completely remove the data cache
1060 | delete cache[ id ];
1061 | }
1062 | }
1063 | });
1064 |
1065 | jQuery.fn.extend({
1066 | data: function( key, value ) {
1067 | if ( typeof key === "undefined" && this.length ) {
1068 | return jQuery.data( this[0] );
1069 |
1070 | } else if ( typeof key === "object" ) {
1071 | return this.each(function() {
1072 | jQuery.data( this, key );
1073 | });
1074 | }
1075 |
1076 | var parts = key.split(".");
1077 | parts[1] = parts[1] ? "." + parts[1] : "";
1078 |
1079 | if ( value === undefined ) {
1080 | var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
1081 |
1082 | if ( data === undefined && this.length ) {
1083 | data = jQuery.data( this[0], key );
1084 | }
1085 | return data === undefined && parts[1] ?
1086 | this.data( parts[0] ) :
1087 | data;
1088 | } else {
1089 | return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() {
1090 | jQuery.data( this, key, value );
1091 | });
1092 | }
1093 | },
1094 |
1095 | removeData: function( key ) {
1096 | return this.each(function() {
1097 | jQuery.removeData( this, key );
1098 | });
1099 | }
1100 | });
1101 | jQuery.extend({
1102 | queue: function( elem, type, data ) {
1103 | if ( !elem ) {
1104 | return;
1105 | }
1106 |
1107 | type = (type || "fx") + "queue";
1108 | var q = jQuery.data( elem, type );
1109 |
1110 | // Speed up dequeue by getting out quickly if this is just a lookup
1111 | if ( !data ) {
1112 | return q || [];
1113 | }
1114 |
1115 | if ( !q || jQuery.isArray(data) ) {
1116 | q = jQuery.data( elem, type, jQuery.makeArray(data) );
1117 |
1118 | } else {
1119 | q.push( data );
1120 | }
1121 |
1122 | return q;
1123 | },
1124 |
1125 | dequeue: function( elem, type ) {
1126 | type = type || "fx";
1127 |
1128 | var queue = jQuery.queue( elem, type ), fn = queue.shift();
1129 |
1130 | // If the fx queue is dequeued, always remove the progress sentinel
1131 | if ( fn === "inprogress" ) {
1132 | fn = queue.shift();
1133 | }
1134 |
1135 | if ( fn ) {
1136 | // Add a progress sentinel to prevent the fx queue from being
1137 | // automatically dequeued
1138 | if ( type === "fx" ) {
1139 | queue.unshift("inprogress");
1140 | }
1141 |
1142 | fn.call(elem, function() {
1143 | jQuery.dequeue(elem, type);
1144 | });
1145 | }
1146 | }
1147 | });
1148 |
1149 | jQuery.fn.extend({
1150 | queue: function( type, data ) {
1151 | if ( typeof type !== "string" ) {
1152 | data = type;
1153 | type = "fx";
1154 | }
1155 |
1156 | if ( data === undefined ) {
1157 | return jQuery.queue( this[0], type );
1158 | }
1159 | return this.each(function( i, elem ) {
1160 | var queue = jQuery.queue( this, type, data );
1161 |
1162 | if ( type === "fx" && queue[0] !== "inprogress" ) {
1163 | jQuery.dequeue( this, type );
1164 | }
1165 | });
1166 | },
1167 | dequeue: function( type ) {
1168 | return this.each(function() {
1169 | jQuery.dequeue( this, type );
1170 | });
1171 | },
1172 |
1173 | // Based off of the plugin by Clint Helfers, with permission.
1174 | // http://blindsignals.com/index.php/2009/07/jquery-delay/
1175 | delay: function( time, type ) {
1176 | time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;
1177 | type = type || "fx";
1178 |
1179 | return this.queue( type, function() {
1180 | var elem = this;
1181 | setTimeout(function() {
1182 | jQuery.dequeue( elem, type );
1183 | }, time );
1184 | });
1185 | },
1186 |
1187 | clearQueue: function( type ) {
1188 | return this.queue( type || "fx", [] );
1189 | }
1190 | });
1191 | var rclass = /[\n\t]/g,
1192 | rspace = /\s+/,
1193 | rreturn = /\r/g,
1194 | rspecialurl = /href|src|style/,
1195 | rtype = /(button|input)/i,
1196 | rfocusable = /(button|input|object|select|textarea)/i,
1197 | rclickable = /^(a|area)$/i,
1198 | rradiocheck = /radio|checkbox/;
1199 |
1200 | jQuery.fn.extend({
1201 | attr: function( name, value ) {
1202 | return access( this, name, value, true, jQuery.attr );
1203 | },
1204 |
1205 | removeAttr: function( name, fn ) {
1206 | return this.each(function(){
1207 | jQuery.attr( this, name, "" );
1208 | if ( this.nodeType === 1 ) {
1209 | this.removeAttribute( name );
1210 | }
1211 | });
1212 | },
1213 |
1214 | addClass: function( value ) {
1215 | if ( jQuery.isFunction(value) ) {
1216 | return this.each(function(i) {
1217 | var self = jQuery(this);
1218 | self.addClass( value.call(this, i, self.attr("class")) );
1219 | });
1220 | }
1221 |
1222 | if ( value && typeof value === "string" ) {
1223 | var classNames = (value || "").split( rspace );
1224 |
1225 | for ( var i = 0, l = this.length; i < l; i++ ) {
1226 | var elem = this[i];
1227 |
1228 | if ( elem.nodeType === 1 ) {
1229 | if ( !elem.className ) {
1230 | elem.className = value;
1231 |
1232 | } else {
1233 | var className = " " + elem.className + " ";
1234 | for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
1235 | if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) {
1236 | elem.className += " " + classNames[c];
1237 | }
1238 | }
1239 | }
1240 | }
1241 | }
1242 | }
1243 |
1244 | return this;
1245 | },
1246 |
1247 | removeClass: function( value ) {
1248 | if ( jQuery.isFunction(value) ) {
1249 | return this.each(function(i) {
1250 | var self = jQuery(this);
1251 | self.removeClass( value.call(this, i, self.attr("class")) );
1252 | });
1253 | }
1254 |
1255 | if ( (value && typeof value === "string") || value === undefined ) {
1256 | var classNames = (value || "").split(rspace);
1257 |
1258 | for ( var i = 0, l = this.length; i < l; i++ ) {
1259 | var elem = this[i];
1260 |
1261 | if ( elem.nodeType === 1 && elem.className ) {
1262 | if ( value ) {
1263 | var className = (" " + elem.className + " ").replace(rclass, " ");
1264 | for ( var c = 0, cl = classNames.length; c < cl; c++ ) {
1265 | className = className.replace(" " + classNames[c] + " ", " ");
1266 | }
1267 | elem.className = className.substring(1, className.length - 1);
1268 |
1269 | } else {
1270 | elem.className = "";
1271 | }
1272 | }
1273 | }
1274 | }
1275 |
1276 | return this;
1277 | },
1278 |
1279 | toggleClass: function( value, stateVal ) {
1280 | var type = typeof value, isBool = typeof stateVal === "boolean";
1281 |
1282 | if ( jQuery.isFunction( value ) ) {
1283 | return this.each(function(i) {
1284 | var self = jQuery(this);
1285 | self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal );
1286 | });
1287 | }
1288 |
1289 | return this.each(function() {
1290 | if ( type === "string" ) {
1291 | // toggle individual class names
1292 | var className, i = 0, self = jQuery(this),
1293 | state = stateVal,
1294 | classNames = value.split( rspace );
1295 |
1296 | while ( (className = classNames[ i++ ]) ) {
1297 | // check each className given, space seperated list
1298 | state = isBool ? state : !self.hasClass( className );
1299 | self[ state ? "addClass" : "removeClass" ]( className );
1300 | }
1301 |
1302 | } else if ( type === "undefined" || type === "boolean" ) {
1303 | if ( this.className ) {
1304 | // store className if set
1305 | jQuery.data( this, "__className__", this.className );
1306 | }
1307 |
1308 | // toggle whole className
1309 | this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || "";
1310 | }
1311 | });
1312 | },
1313 |
1314 | hasClass: function( selector ) {
1315 | var className = " " + selector + " ";
1316 | for ( var i = 0, l = this.length; i < l; i++ ) {
1317 | if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) {
1318 | return true;
1319 | }
1320 | }
1321 |
1322 | return false;
1323 | },
1324 |
1325 | val: function( value ) {
1326 | if ( value === undefined ) {
1327 | var elem = this[0];
1328 |
1329 | if ( elem ) {
1330 | if ( jQuery.nodeName( elem, "option" ) ) {
1331 | return (elem.attributes.value || {}).specified ? elem.value : elem.text;
1332 | }
1333 |
1334 | // We need to handle select boxes special
1335 | if ( jQuery.nodeName( elem, "select" ) ) {
1336 | var index = elem.selectedIndex,
1337 | values = [],
1338 | options = elem.options,
1339 | one = elem.type === "select-one";
1340 |
1341 | // Nothing was selected
1342 | if ( index < 0 ) {
1343 | return null;
1344 | }
1345 |
1346 | // Loop through all the selected options
1347 | for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {
1348 | var option = options[ i ];
1349 |
1350 | if ( option.selected ) {
1351 | // Get the specifc value for the option
1352 | value = jQuery(option).val();
1353 |
1354 | // We don't need an array for one selects
1355 | if ( one ) {
1356 | return value;
1357 | }
1358 |
1359 | // Multi-Selects return an array
1360 | values.push( value );
1361 | }
1362 | }
1363 |
1364 | return values;
1365 | }
1366 |
1367 | // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified
1368 | if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {
1369 | return elem.getAttribute("value") === null ? "on" : elem.value;
1370 | }
1371 |
1372 |
1373 | // Everything else, we just grab the value
1374 | return (elem.value || "").replace(rreturn, "");
1375 |
1376 | }
1377 |
1378 | return undefined;
1379 | }
1380 |
1381 | var isFunction = jQuery.isFunction(value);
1382 |
1383 | return this.each(function(i) {
1384 | var self = jQuery(this), val = value;
1385 |
1386 | if ( this.nodeType !== 1 ) {
1387 | return;
1388 | }
1389 |
1390 | if ( isFunction ) {
1391 | val = value.call(this, i, self.val());
1392 | }
1393 |
1394 | // Typecast each time if the value is a Function and the appended
1395 | // value is therefore different each time.
1396 | if ( typeof val === "number" ) {
1397 | val += "";
1398 | }
1399 |
1400 | if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {
1401 | this.checked = jQuery.inArray( self.val(), val ) >= 0;
1402 |
1403 | } else if ( jQuery.nodeName( this, "select" ) ) {
1404 | var values = jQuery.makeArray(val);
1405 |
1406 | jQuery( "option", this ).each(function() {
1407 | this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;
1408 | });
1409 |
1410 | if ( !values.length ) {
1411 | this.selectedIndex = -1;
1412 | }
1413 |
1414 | } else {
1415 | this.value = val;
1416 | }
1417 | });
1418 | }
1419 | });
1420 |
1421 | jQuery.extend({
1422 | attrFn: {
1423 | val: true,
1424 | css: true,
1425 | html: true,
1426 | text: true,
1427 | data: true,
1428 | width: true,
1429 | height: true,
1430 | offset: true
1431 | },
1432 |
1433 | attr: function( elem, name, value, pass ) {
1434 | // don't set attributes on text and comment nodes
1435 | if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
1436 | return undefined;
1437 | }
1438 |
1439 | if ( pass && name in jQuery.attrFn ) {
1440 | return jQuery(elem)[name](value);
1441 | }
1442 |
1443 | var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),
1444 | // Whether we are setting (or getting)
1445 | set = value !== undefined;
1446 |
1447 | // Try to normalize/fix the name
1448 | name = notxml && jQuery.props[ name ] || name;
1449 |
1450 | // Only do all the following if this is a node (faster for style)
1451 | if ( elem.nodeType === 1 ) {
1452 | // These attributes require special treatment
1453 | var special = rspecialurl.test( name );
1454 |
1455 | // Safari mis-reports the default selected property of an option
1456 | // Accessing the parent's selectedIndex property fixes it
1457 | if ( name === "selected" && !jQuery.support.optSelected ) {
1458 | var parent = elem.parentNode;
1459 | if ( parent ) {
1460 | parent.selectedIndex;
1461 |
1462 | // Make sure that it also works with optgroups, see #5701
1463 | if ( parent.parentNode ) {
1464 | parent.parentNode.selectedIndex;
1465 | }
1466 | }
1467 | }
1468 |
1469 | // If applicable, access the attribute via the DOM 0 way
1470 | if ( name in elem && notxml && !special ) {
1471 | if ( set ) {
1472 | // We can't allow the type property to be changed (since it causes problems in IE)
1473 | if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) {
1474 | jQuery.error( "type property can't be changed" );
1475 | }
1476 |
1477 | elem[ name ] = value;
1478 | }
1479 |
1480 | // browsers index elements by id/name on forms, give priority to attributes.
1481 | if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) {
1482 | return elem.getAttributeNode( name ).nodeValue;
1483 | }
1484 |
1485 | // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set
1486 | // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
1487 | if ( name === "tabIndex" ) {
1488 | var attributeNode = elem.getAttributeNode( "tabIndex" );
1489 |
1490 | return attributeNode && attributeNode.specified ?
1491 | attributeNode.value :
1492 | rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?
1493 | 0 :
1494 | undefined;
1495 | }
1496 |
1497 | return elem[ name ];
1498 | }
1499 |
1500 | if ( !jQuery.support.style && notxml && name === "style" ) {
1501 | if ( set ) {
1502 | elem.style.cssText = "" + value;
1503 | }
1504 |
1505 | return elem.style.cssText;
1506 | }
1507 |
1508 | if ( set ) {
1509 | // convert the value to a string (all browsers do this but IE) see #1070
1510 | elem.setAttribute( name, "" + value );
1511 | }
1512 |
1513 | var attr = !jQuery.support.hrefNormalized && notxml && special ?
1514 | // Some attributes require a special call on IE
1515 | elem.getAttribute( name, 2 ) :
1516 | elem.getAttribute( name );
1517 |
1518 | // Non-existent attributes return null, we normalize to undefined
1519 | return attr === null ? undefined : attr;
1520 | }
1521 |
1522 | // elem is actually elem.style ... set the style
1523 | // Using attr for specific style information is now deprecated. Use style insead.
1524 | return jQuery.style( elem, name, value );
1525 | }
1526 | });
1527 | var fcleanup = function( nm ) {
1528 | return nm.replace(/[^\w\s\.\|`]/g, function( ch ) {
1529 | return "\\" + ch;
1530 | });
1531 | };
1532 |
1533 | /*
1534 | * A number of helper functions used for managing events.
1535 | * Many of the ideas behind this code originated from
1536 | * Dean Edwards' addEvent library.
1537 | */
1538 | jQuery.event = {
1539 |
1540 | // Bind an event to an element
1541 | // Original by Dean Edwards
1542 | add: function( elem, types, handler, data ) {
1543 | if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
1544 | return;
1545 | }
1546 |
1547 | // For whatever reason, IE has trouble passing the window object
1548 | // around, causing it to be cloned in the process
1549 | if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) {
1550 | elem = window;
1551 | }
1552 |
1553 | // Make sure that the function being executed has a unique ID
1554 | if ( !handler.guid ) {
1555 | handler.guid = jQuery.guid++;
1556 | }
1557 |
1558 | // if data is passed, bind to handler
1559 | if ( data !== undefined ) {
1560 | // Create temporary function pointer to original handler
1561 | var fn = handler;
1562 |
1563 | // Create unique handler function, wrapped around original handler
1564 | handler = jQuery.proxy( fn );
1565 |
1566 | // Store data in unique handler
1567 | handler.data = data;
1568 | }
1569 |
1570 | // Init the element's event structure
1571 | var events = jQuery.data( elem, "events" ) || jQuery.data( elem, "events", {} ),
1572 | handle = jQuery.data( elem, "handle" ), eventHandle;
1573 |
1574 | if ( !handle ) {
1575 | eventHandle = function() {
1576 | // Handle the second event of a trigger and when
1577 | // an event is called after a page has unloaded
1578 | return typeof jQuery !== "undefined" && !jQuery.event.triggered ?
1579 | jQuery.event.handle.apply( eventHandle.elem, arguments ) :
1580 | undefined;
1581 | };
1582 |
1583 | handle = jQuery.data( elem, "handle", eventHandle );
1584 | }
1585 |
1586 | // If no handle is found then we must be trying to bind to one of the
1587 | // banned noData elements
1588 | if ( !handle ) {
1589 | return;
1590 | }
1591 |
1592 | // Add elem as a property of the handle function
1593 | // This is to prevent a memory leak with non-native
1594 | // event in IE.
1595 | handle.elem = elem;
1596 |
1597 | // Handle multiple events separated by a space
1598 | // jQuery(...).bind("mouseover mouseout", fn);
1599 | types = types.split( /\s+/ );
1600 |
1601 | var type, i = 0;
1602 |
1603 | while ( (type = types[ i++ ]) ) {
1604 | // Namespaced event handlers
1605 | var namespaces = type.split(".");
1606 | type = namespaces.shift();
1607 |
1608 | if ( i > 1 ) {
1609 | handler = jQuery.proxy( handler );
1610 |
1611 | if ( data !== undefined ) {
1612 | handler.data = data;
1613 | }
1614 | }
1615 |
1616 | handler.type = namespaces.slice(0).sort().join(".");
1617 |
1618 | // Get the current list of functions bound to this event
1619 | var handlers = events[ type ],
1620 | special = this.special[ type ] || {};
1621 |
1622 | // Init the event handler queue
1623 | if ( !handlers ) {
1624 | handlers = events[ type ] = {};
1625 |
1626 | // Check for a special event handler
1627 | // Only use addEventListener/attachEvent if the special
1628 | // events handler returns false
1629 | if ( !special.setup || special.setup.call( elem, data, namespaces, handler) === false ) {
1630 | // Bind the global event handler to the element
1631 | if ( elem.addEventListener ) {
1632 | elem.addEventListener( type, handle, false );
1633 | } else if ( elem.attachEvent ) {
1634 | elem.attachEvent( "on" + type, handle );
1635 | }
1636 | }
1637 | }
1638 |
1639 | if ( special.add ) {
1640 | var modifiedHandler = special.add.call( elem, handler, data, namespaces, handlers );
1641 | if ( modifiedHandler && jQuery.isFunction( modifiedHandler ) ) {
1642 | modifiedHandler.guid = modifiedHandler.guid || handler.guid;
1643 | modifiedHandler.data = modifiedHandler.data || handler.data;
1644 | modifiedHandler.type = modifiedHandler.type || handler.type;
1645 | handler = modifiedHandler;
1646 | }
1647 | }
1648 |
1649 | // Add the function to the element's handler list
1650 | handlers[ handler.guid ] = handler;
1651 |
1652 | // Keep track of which events have been used, for global triggering
1653 | this.global[ type ] = true;
1654 | }
1655 |
1656 | // Nullify elem to prevent memory leaks in IE
1657 | elem = null;
1658 | },
1659 |
1660 | global: {},
1661 |
1662 | // Detach an event or set of events from an element
1663 | remove: function( elem, types, handler ) {
1664 | // don't do events on text and comment nodes
1665 | if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
1666 | return;
1667 | }
1668 |
1669 | var events = jQuery.data( elem, "events" ), ret, type, fn;
1670 |
1671 | if ( events ) {
1672 | // Unbind all events for the element
1673 | if ( types === undefined || (typeof types === "string" && types.charAt(0) === ".") ) {
1674 | for ( type in events ) {
1675 | this.remove( elem, type + (types || "") );
1676 | }
1677 | } else {
1678 | // types is actually an event object here
1679 | if ( types.type ) {
1680 | handler = types.handler;
1681 | types = types.type;
1682 | }
1683 |
1684 | // Handle multiple events separated by a space
1685 | // jQuery(...).unbind("mouseover mouseout", fn);
1686 | types = types.split(/\s+/);
1687 | var i = 0;
1688 | while ( (type = types[ i++ ]) ) {
1689 | // Namespaced event handlers
1690 | var namespaces = type.split(".");
1691 | type = namespaces.shift();
1692 | var all = !namespaces.length,
1693 | cleaned = jQuery.map( namespaces.slice(0).sort(), fcleanup ),
1694 | namespace = new RegExp("(^|\\.)" + cleaned.join("\\.(?:.*\\.)?") + "(\\.|$)"),
1695 | special = this.special[ type ] || {};
1696 |
1697 | if ( events[ type ] ) {
1698 | // remove the given handler for the given type
1699 | if ( handler ) {
1700 | fn = events[ type ][ handler.guid ];
1701 | delete events[ type ][ handler.guid ];
1702 |
1703 | // remove all handlers for the given type
1704 | } else {
1705 | for ( var handle in events[ type ] ) {
1706 | // Handle the removal of namespaced events
1707 | if ( all || namespace.test( events[ type ][ handle ].type ) ) {
1708 | delete events[ type ][ handle ];
1709 | }
1710 | }
1711 | }
1712 |
1713 | if ( special.remove ) {
1714 | special.remove.call( elem, namespaces, fn);
1715 | }
1716 |
1717 | // remove generic event handler if no more handlers exist
1718 | for ( ret in events[ type ] ) {
1719 | break;
1720 | }
1721 | if ( !ret ) {
1722 | if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {
1723 | if ( elem.removeEventListener ) {
1724 | elem.removeEventListener( type, jQuery.data( elem, "handle" ), false );
1725 | } else if ( elem.detachEvent ) {
1726 | elem.detachEvent( "on" + type, jQuery.data( elem, "handle" ) );
1727 | }
1728 | }
1729 | ret = null;
1730 | delete events[ type ];
1731 | }
1732 | }
1733 | }
1734 | }
1735 |
1736 | // Remove the expando if it's no longer used
1737 | for ( ret in events ) {
1738 | break;
1739 | }
1740 | if ( !ret ) {
1741 | var handle = jQuery.data( elem, "handle" );
1742 | if ( handle ) {
1743 | handle.elem = null;
1744 | }
1745 | jQuery.removeData( elem, "events" );
1746 | jQuery.removeData( elem, "handle" );
1747 | }
1748 | }
1749 | },
1750 |
1751 | // bubbling is internal
1752 | trigger: function( event, data, elem /*, bubbling */ ) {
1753 | // Event object or event type
1754 | var type = event.type || event,
1755 | bubbling = arguments[3];
1756 |
1757 | if ( !bubbling ) {
1758 | event = typeof event === "object" ?
1759 | // jQuery.Event object
1760 | event[expando] ? event :
1761 | // Object literal
1762 | jQuery.extend( jQuery.Event(type), event ) :
1763 | // Just the event type (string)
1764 | jQuery.Event(type);
1765 |
1766 | if ( type.indexOf("!") >= 0 ) {
1767 | event.type = type = type.slice(0, -1);
1768 | event.exclusive = true;
1769 | }
1770 |
1771 | // Handle a global trigger
1772 | if ( !elem ) {
1773 | // Don't bubble custom events when global (to avoid too much overhead)
1774 | event.stopPropagation();
1775 |
1776 | // Only trigger if we've ever bound an event for it
1777 | if ( this.global[ type ] ) {
1778 | jQuery.each( jQuery.cache, function() {
1779 | if ( this.events && this.events[type] ) {
1780 | jQuery.event.trigger( event, data, this.handle.elem );
1781 | }
1782 | });
1783 | }
1784 | }
1785 |
1786 | // Handle triggering a single element
1787 |
1788 | // don't do events on text and comment nodes
1789 | if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {
1790 | return undefined;
1791 | }
1792 |
1793 | // Clean up in case it is reused
1794 | event.result = undefined;
1795 | event.target = elem;
1796 |
1797 | // Clone the incoming data, if any
1798 | data = jQuery.makeArray( data );
1799 | data.unshift( event );
1800 | }
1801 |
1802 | event.currentTarget = elem;
1803 |
1804 | // Trigger the event, it is assumed that "handle" is a function
1805 | var handle = jQuery.data( elem, "handle" );
1806 | if ( handle ) {
1807 | handle.apply( elem, data );
1808 | }
1809 |
1810 | var parent = elem.parentNode || elem.ownerDocument;
1811 |
1812 | // Trigger an inline bound script
1813 | try {
1814 | if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {
1815 | if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) {
1816 | event.result = false;
1817 | }
1818 | }
1819 |
1820 | // prevent IE from throwing an error for some elements with some event types, see #3533
1821 | } catch (e) {}
1822 |
1823 | if ( !event.isPropagationStopped() && parent ) {
1824 | jQuery.event.trigger( event, data, parent, true );
1825 |
1826 | } else if ( !event.isDefaultPrevented() ) {
1827 | var target = event.target, old,
1828 | isClick = jQuery.nodeName(target, "a") && type === "click";
1829 |
1830 | if ( !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {
1831 | try {
1832 | if ( target[ type ] ) {
1833 | // Make sure that we don't accidentally re-trigger the onFOO events
1834 | old = target[ "on" + type ];
1835 |
1836 | if ( old ) {
1837 | target[ "on" + type ] = null;
1838 | }
1839 |
1840 | this.triggered = true;
1841 | target[ type ]();
1842 | }
1843 |
1844 | // prevent IE from throwing an error for some elements with some event types, see #3533
1845 | } catch (e) {}
1846 |
1847 | if ( old ) {
1848 | target[ "on" + type ] = old;
1849 | }
1850 |
1851 | this.triggered = false;
1852 | }
1853 | }
1854 | },
1855 |
1856 | handle: function( event ) {
1857 | // returned undefined or false
1858 | var all, handlers;
1859 |
1860 | event = arguments[0] = jQuery.event.fix( event || window.event );
1861 | event.currentTarget = this;
1862 |
1863 | // Namespaced event handlers
1864 | var namespaces = event.type.split(".");
1865 | event.type = namespaces.shift();
1866 |
1867 | // Cache this now, all = true means, any handler
1868 | all = !namespaces.length && !event.exclusive;
1869 |
1870 | var namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
1871 |
1872 | handlers = ( jQuery.data(this, "events") || {} )[ event.type ];
1873 |
1874 | for ( var j in handlers ) {
1875 | var handler = handlers[ j ];
1876 |
1877 | // Filter the functions by class
1878 | if ( all || namespace.test(handler.type) ) {
1879 | // Pass in a reference to the handler function itself
1880 | // So that we can later remove it
1881 | event.handler = handler;
1882 | event.data = handler.data;
1883 |
1884 | var ret = handler.apply( this, arguments );
1885 |
1886 | if ( ret !== undefined ) {
1887 | event.result = ret;
1888 | if ( ret === false ) {
1889 | event.preventDefault();
1890 | event.stopPropagation();
1891 | }
1892 | }
1893 |
1894 | if ( event.isImmediatePropagationStopped() ) {
1895 | break;
1896 | }
1897 |
1898 | }
1899 | }
1900 |
1901 | return event.result;
1902 | },
1903 |
1904 | props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
1905 |
1906 | fix: function( event ) {
1907 | if ( event[ expando ] ) {
1908 | return event;
1909 | }
1910 |
1911 | // store a copy of the original event object
1912 | // and "clone" to set read-only properties
1913 | var originalEvent = event;
1914 | event = jQuery.Event( originalEvent );
1915 |
1916 | for ( var i = this.props.length, prop; i; ) {
1917 | prop = this.props[ --i ];
1918 | event[ prop ] = originalEvent[ prop ];
1919 | }
1920 |
1921 | // Fix target property, if necessary
1922 | if ( !event.target ) {
1923 | event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either
1924 | }
1925 |
1926 | // check if target is a textnode (safari)
1927 | if ( event.target.nodeType === 3 ) {
1928 | event.target = event.target.parentNode;
1929 | }
1930 |
1931 | // Add relatedTarget, if necessary
1932 | if ( !event.relatedTarget && event.fromElement ) {
1933 | event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;
1934 | }
1935 |
1936 | // Calculate pageX/Y if missing and clientX/Y available
1937 | if ( event.pageX == null && event.clientX != null ) {
1938 | var doc = document.documentElement, body = document.body;
1939 | event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
1940 | event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
1941 | }
1942 |
1943 | // Add which for key events
1944 | if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) {
1945 | event.which = event.charCode || event.keyCode;
1946 | }
1947 |
1948 | // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
1949 | if ( !event.metaKey && event.ctrlKey ) {
1950 | event.metaKey = event.ctrlKey;
1951 | }
1952 |
1953 | // Add which for click: 1 === left; 2 === middle; 3 === right
1954 | // Note: button is not normalized, so don't use it
1955 | if ( !event.which && event.button !== undefined ) {
1956 | event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));
1957 | }
1958 |
1959 | return event;
1960 | },
1961 |
1962 | // Deprecated, use jQuery.guid instead
1963 | guid: 1E8,
1964 |
1965 | // Deprecated, use jQuery.proxy instead
1966 | proxy: jQuery.proxy,
1967 |
1968 | special: {
1969 | ready: {
1970 | // Make sure the ready event is setup
1971 | setup: jQuery.bindReady,
1972 | teardown: jQuery.noop
1973 | },
1974 |
1975 | live: {
1976 | add: function( proxy, data, namespaces, live ) {
1977 | jQuery.extend( proxy, data || {} );
1978 |
1979 | proxy.guid += data.selector + data.live;
1980 | data.liveProxy = proxy;
1981 |
1982 | jQuery.event.add( this, data.live, liveHandler, data );
1983 |
1984 | },
1985 |
1986 | remove: function( namespaces ) {
1987 | if ( namespaces.length ) {
1988 | var remove = 0, name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");
1989 |
1990 | jQuery.each( (jQuery.data(this, "events").live || {}), function() {
1991 | if ( name.test(this.type) ) {
1992 | remove++;
1993 | }
1994 | });
1995 |
1996 | if ( remove < 1 ) {
1997 | jQuery.event.remove( this, namespaces[0], liveHandler );
1998 | }
1999 | }
2000 | },
2001 | special: {}
2002 | },
2003 | beforeunload: {
2004 | setup: function( data, namespaces, fn ) {
2005 | // We only want to do this special case on windows
2006 | if ( this.setInterval ) {
2007 | this.onbeforeunload = fn;
2008 | }
2009 |
2010 | return false;
2011 | },
2012 | teardown: function( namespaces, fn ) {
2013 | if ( this.onbeforeunload === fn ) {
2014 | this.onbeforeunload = null;
2015 | }
2016 | }
2017 | }
2018 | }
2019 | };
2020 |
2021 | jQuery.Event = function( src ) {
2022 | // Allow instantiation without the 'new' keyword
2023 | if ( !this.preventDefault ) {
2024 | return new jQuery.Event( src );
2025 | }
2026 |
2027 | // Event object
2028 | if ( src && src.type ) {
2029 | this.originalEvent = src;
2030 | this.type = src.type;
2031 | // Event type
2032 | } else {
2033 | this.type = src;
2034 | }
2035 |
2036 | // timeStamp is buggy for some events on Firefox(#3843)
2037 | // So we won't rely on the native value
2038 | this.timeStamp = now();
2039 |
2040 | // Mark it as fixed
2041 | this[ expando ] = true;
2042 | };
2043 |
2044 | function returnFalse() {
2045 | return false;
2046 | }
2047 | function returnTrue() {
2048 | return true;
2049 | }
2050 |
2051 | // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
2052 | // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
2053 | jQuery.Event.prototype = {
2054 | preventDefault: function() {
2055 | this.isDefaultPrevented = returnTrue;
2056 |
2057 | var e = this.originalEvent;
2058 | if ( !e ) {
2059 | return;
2060 | }
2061 |
2062 | // if preventDefault exists run it on the original event
2063 | if ( e.preventDefault ) {
2064 | e.preventDefault();
2065 | }
2066 | // otherwise set the returnValue property of the original event to false (IE)
2067 | e.returnValue = false;
2068 | },
2069 | stopPropagation: function() {
2070 | this.isPropagationStopped = returnTrue;
2071 |
2072 | var e = this.originalEvent;
2073 | if ( !e ) {
2074 | return;
2075 | }
2076 | // if stopPropagation exists run it on the original event
2077 | if ( e.stopPropagation ) {
2078 | e.stopPropagation();
2079 | }
2080 | // otherwise set the cancelBubble property of the original event to true (IE)
2081 | e.cancelBubble = true;
2082 | },
2083 | stopImmediatePropagation: function() {
2084 | this.isImmediatePropagationStopped = returnTrue;
2085 | this.stopPropagation();
2086 | },
2087 | isDefaultPrevented: returnFalse,
2088 | isPropagationStopped: returnFalse,
2089 | isImmediatePropagationStopped: returnFalse
2090 | };
2091 |
2092 | // Checks if an event happened on an element within another element
2093 | // Used in jQuery.event.special.mouseenter and mouseleave handlers
2094 | var withinElement = function( event ) {
2095 | // Check if mouse(over|out) are still within the same parent element
2096 | var parent = event.relatedTarget;
2097 |
2098 | // Traverse up the tree
2099 | while ( parent && parent !== this ) {
2100 | // Firefox sometimes assigns relatedTarget a XUL element
2101 | // which we cannot access the parentNode property of
2102 | try {
2103 | parent = parent.parentNode;
2104 |
2105 | // assuming we've left the element since we most likely mousedover a xul element
2106 | } catch(e) {
2107 | break;
2108 | }
2109 | }
2110 |
2111 | if ( parent !== this ) {
2112 | // set the correct event type
2113 | event.type = event.data;
2114 |
2115 | // handle event if we actually just moused on to a non sub-element
2116 | jQuery.event.handle.apply( this, arguments );
2117 | }
2118 |
2119 | },
2120 |
2121 | // In case of event delegation, we only need to rename the event.type,
2122 | // liveHandler will take care of the rest.
2123 | delegate = function( event ) {
2124 | event.type = event.data;
2125 | jQuery.event.handle.apply( this, arguments );
2126 | };
2127 |
2128 | // Create mouseenter and mouseleave events
2129 | jQuery.each({
2130 | mouseenter: "mouseover",
2131 | mouseleave: "mouseout"
2132 | }, function( orig, fix ) {
2133 | jQuery.event.special[ orig ] = {
2134 | setup: function( data ) {
2135 | jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );
2136 | },
2137 | teardown: function( data ) {
2138 | jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );
2139 | }
2140 | };
2141 | });
2142 |
2143 | // submit delegation
2144 | if ( !jQuery.support.submitBubbles ) {
2145 |
2146 | jQuery.event.special.submit = {
2147 | setup: function( data, namespaces, fn ) {
2148 | if ( this.nodeName.toLowerCase() !== "form" ) {
2149 | jQuery.event.add(this, "click.specialSubmit." + fn.guid, function( e ) {
2150 | var elem = e.target, type = elem.type;
2151 |
2152 | if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) {
2153 | return trigger( "submit", this, arguments );
2154 | }
2155 | });
2156 |
2157 | jQuery.event.add(this, "keypress.specialSubmit." + fn.guid, function( e ) {
2158 | var elem = e.target, type = elem.type;
2159 |
2160 | if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) {
2161 | return trigger( "submit", this, arguments );
2162 | }
2163 | });
2164 |
2165 | } else {
2166 | return false;
2167 | }
2168 | },
2169 |
2170 | remove: function( namespaces, fn ) {
2171 | jQuery.event.remove( this, "click.specialSubmit" + (fn ? "."+fn.guid : "") );
2172 | jQuery.event.remove( this, "keypress.specialSubmit" + (fn ? "."+fn.guid : "") );
2173 | }
2174 | };
2175 |
2176 | }
2177 |
2178 | // change delegation, happens here so we have bind.
2179 | if ( !jQuery.support.changeBubbles ) {
2180 |
2181 | var formElems = /textarea|input|select/i;
2182 |
2183 | function getVal( elem ) {
2184 | var type = elem.type, val = elem.value;
2185 |
2186 | if ( type === "radio" || type === "checkbox" ) {
2187 | val = elem.checked;
2188 |
2189 | } else if ( type === "select-multiple" ) {
2190 | val = elem.selectedIndex > -1 ?
2191 | jQuery.map( elem.options, function( elem ) {
2192 | return elem.selected;
2193 | }).join("-") :
2194 | "";
2195 |
2196 | } else if ( elem.nodeName.toLowerCase() === "select" ) {
2197 | val = elem.selectedIndex;
2198 | }
2199 |
2200 | return val;
2201 | }
2202 |
2203 | function testChange( e ) {
2204 | var elem = e.target, data, val;
2205 |
2206 | if ( !formElems.test( elem.nodeName ) || elem.readOnly ) {
2207 | return;
2208 | }
2209 |
2210 | data = jQuery.data( elem, "_change_data" );
2211 | val = getVal(elem);
2212 |
2213 | // the current data will be also retrieved by beforeactivate
2214 | if ( e.type !== "focusout" || elem.type !== "radio" ) {
2215 | jQuery.data( elem, "_change_data", val );
2216 | }
2217 |
2218 | if ( data === undefined || val === data ) {
2219 | return;
2220 | }
2221 |
2222 | if ( data != null || val ) {
2223 | e.type = "change";
2224 | return jQuery.event.trigger( e, arguments[1], elem );
2225 | }
2226 | }
2227 |
2228 | jQuery.event.special.change = {
2229 | filters: {
2230 | focusout: testChange,
2231 |
2232 | click: function( e ) {
2233 | var elem = e.target, type = elem.type;
2234 |
2235 | if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) {
2236 | return testChange.call( this, e );
2237 | }
2238 | },
2239 |
2240 | // Change has to be called before submit
2241 | // Keydown will be called before keypress, which is used in submit-event delegation
2242 | keydown: function( e ) {
2243 | var elem = e.target, type = elem.type;
2244 |
2245 | if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") ||
2246 | (e.keyCode === 32 && (type === "checkbox" || type === "radio")) ||
2247 | type === "select-multiple" ) {
2248 | return testChange.call( this, e );
2249 | }
2250 | },
2251 |
2252 | // Beforeactivate happens also before the previous element is blurred
2253 | // with this event you can't trigger a change event, but you can store
2254 | // information/focus[in] is not needed anymore
2255 | beforeactivate: function( e ) {
2256 | var elem = e.target;
2257 |
2258 | if ( elem.nodeName.toLowerCase() === "input" && elem.type === "radio" ) {
2259 | jQuery.data( elem, "_change_data", getVal(elem) );
2260 | }
2261 | }
2262 | },
2263 | setup: function( data, namespaces, fn ) {
2264 | for ( var type in changeFilters ) {
2265 | jQuery.event.add( this, type + ".specialChange." + fn.guid, changeFilters[type] );
2266 | }
2267 |
2268 | return formElems.test( this.nodeName );
2269 | },
2270 | remove: function( namespaces, fn ) {
2271 | for ( var type in changeFilters ) {
2272 | jQuery.event.remove( this, type + ".specialChange" + (fn ? "."+fn.guid : ""), changeFilters[type] );
2273 | }
2274 |
2275 | return formElems.test( this.nodeName );
2276 | }
2277 | };
2278 |
2279 | var changeFilters = jQuery.event.special.change.filters;
2280 |
2281 | }
2282 |
2283 | function trigger( type, elem, args ) {
2284 | args[0].type = type;
2285 | return jQuery.event.handle.apply( elem, args );
2286 | }
2287 |
2288 | // Create "bubbling" focus and blur events
2289 | if ( document.addEventListener ) {
2290 | jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
2291 | jQuery.event.special[ fix ] = {
2292 | setup: function() {
2293 | this.addEventListener( orig, handler, true );
2294 | },
2295 | teardown: function() {
2296 | this.removeEventListener( orig, handler, true );
2297 | }
2298 | };
2299 |
2300 | function handler( e ) {
2301 | e = jQuery.event.fix( e );
2302 | e.type = fix;
2303 | return jQuery.event.handle.call( this, e );
2304 | }
2305 | });
2306 | }
2307 |
2308 | jQuery.each(["bind", "one"], function( i, name ) {
2309 | jQuery.fn[ name ] = function( type, data, fn ) {
2310 | // Handle object literals
2311 | if ( typeof type === "object" ) {
2312 | for ( var key in type ) {
2313 | this[ name ](key, data, type[key], fn);
2314 | }
2315 | return this;
2316 | }
2317 |
2318 | if ( jQuery.isFunction( data ) ) {
2319 | fn = data;
2320 | data = undefined;
2321 | }
2322 |
2323 | var handler = name === "one" ? jQuery.proxy( fn, function( event ) {
2324 | jQuery( this ).unbind( event, handler );
2325 | return fn.apply( this, arguments );
2326 | }) : fn;
2327 |
2328 | return type === "unload" && name !== "one" ?
2329 | this.one( type, data, fn ) :
2330 | this.each(function() {
2331 | jQuery.event.add( this, type, handler, data );
2332 | });
2333 | };
2334 | });
2335 |
2336 | jQuery.fn.extend({
2337 | unbind: function( type, fn ) {
2338 | // Handle object literals
2339 | if ( typeof type === "object" && !type.preventDefault ) {
2340 | for ( var key in type ) {
2341 | this.unbind(key, type[key]);
2342 | }
2343 | return this;
2344 | }
2345 |
2346 | return this.each(function() {
2347 | jQuery.event.remove( this, type, fn );
2348 | });
2349 | },
2350 | trigger: function( type, data ) {
2351 | return this.each(function() {
2352 | jQuery.event.trigger( type, data, this );
2353 | });
2354 | },
2355 |
2356 | triggerHandler: function( type, data ) {
2357 | if ( this[0] ) {
2358 | var event = jQuery.Event( type );
2359 | event.preventDefault();
2360 | event.stopPropagation();
2361 | jQuery.event.trigger( event, data, this[0] );
2362 | return event.result;
2363 | }
2364 | },
2365 |
2366 | toggle: function( fn ) {
2367 | // Save reference to arguments for access in closure
2368 | var args = arguments, i = 1;
2369 |
2370 | // link all the functions, so any of them can unbind this click handler
2371 | while ( i < args.length ) {
2372 | jQuery.proxy( fn, args[ i++ ] );
2373 | }
2374 |
2375 | return this.click( jQuery.proxy( fn, function( event ) {
2376 | // Figure out which function to execute
2377 | var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i;
2378 | jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 );
2379 |
2380 | // Make sure that clicks stop
2381 | event.preventDefault();
2382 |
2383 | // and execute the function
2384 | return args[ lastToggle ].apply( this, arguments ) || false;
2385 | }));
2386 | },
2387 |
2388 | hover: function( fnOver, fnOut ) {
2389 | return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
2390 | }
2391 | });
2392 |
2393 | jQuery.each(["live", "die"], function( i, name ) {
2394 | jQuery.fn[ name ] = function( types, data, fn ) {
2395 | var type, i = 0;
2396 |
2397 | if ( jQuery.isFunction( data ) ) {
2398 | fn = data;
2399 | data = undefined;
2400 | }
2401 |
2402 | types = (types || "").split( /\s+/ );
2403 |
2404 | while ( (type = types[ i++ ]) != null ) {
2405 | type = type === "focus" ? "focusin" : // focus --> focusin
2406 | type === "blur" ? "focusout" : // blur --> focusout
2407 | type === "hover" ? types.push("mouseleave") && "mouseenter" : // hover support
2408 | type;
2409 |
2410 | if ( name === "live" ) {
2411 | // bind live handler
2412 | jQuery( this.context ).bind( liveConvert( type, this.selector ), {
2413 | data: data, selector: this.selector, live: type
2414 | }, fn );
2415 |
2416 | } else {
2417 | // unbind live handler
2418 | jQuery( this.context ).unbind( liveConvert( type, this.selector ), fn ? { guid: fn.guid + this.selector + type } : null );
2419 | }
2420 | }
2421 |
2422 | return this;
2423 | }
2424 | });
2425 |
2426 | function liveHandler( event ) {
2427 | var stop, elems = [], selectors = [], args = arguments,
2428 | related, match, fn, elem, j, i, l, data,
2429 | live = jQuery.extend({}, jQuery.data( this, "events" ).live);
2430 |
2431 | // Make sure we avoid non-left-click bubbling in Firefox (#3861)
2432 | if ( event.button && event.type === "click" ) {
2433 | return;
2434 | }
2435 |
2436 | for ( j in live ) {
2437 | fn = live[j];
2438 | if ( fn.live === event.type ||
2439 | fn.altLive && jQuery.inArray(event.type, fn.altLive) > -1 ) {
2440 |
2441 | data = fn.data;
2442 | if ( !(data.beforeFilter && data.beforeFilter[event.type] &&
2443 | !data.beforeFilter[event.type](event)) ) {
2444 | selectors.push( fn.selector );
2445 | }
2446 | } else {
2447 | delete live[j];
2448 | }
2449 | }
2450 |
2451 | match = jQuery( event.target ).closest( selectors, event.currentTarget );
2452 |
2453 | for ( i = 0, l = match.length; i < l; i++ ) {
2454 | for ( j in live ) {
2455 | fn = live[j];
2456 | elem = match[i].elem;
2457 | related = null;
2458 |
2459 | if ( match[i].selector === fn.selector ) {
2460 | // Those two events require additional checking
2461 | if ( fn.live === "mouseenter" || fn.live === "mouseleave" ) {
2462 | related = jQuery( event.relatedTarget ).closest( fn.selector )[0];
2463 | }
2464 |
2465 | if ( !related || related !== elem ) {
2466 | elems.push({ elem: elem, fn: fn });
2467 | }
2468 | }
2469 | }
2470 | }
2471 |
2472 | for ( i = 0, l = elems.length; i < l; i++ ) {
2473 | match = elems[i];
2474 | event.currentTarget = match.elem;
2475 | event.data = match.fn.data;
2476 | if ( match.fn.apply( match.elem, args ) === false ) {
2477 | stop = false;
2478 | break;
2479 | }
2480 | }
2481 |
2482 | return stop;
2483 | }
2484 |
2485 | function liveConvert( type, selector ) {
2486 | return "live." + (type ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&");
2487 | }
2488 |
2489 | jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
2490 | "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
2491 | "change select submit keydown keypress keyup error").split(" "), function( i, name ) {
2492 |
2493 | // Handle event binding
2494 | jQuery.fn[ name ] = function( fn ) {
2495 | return fn ? this.bind( name, fn ) : this.trigger( name );
2496 | };
2497 |
2498 | if ( jQuery.attrFn ) {
2499 | jQuery.attrFn[ name ] = true;
2500 | }
2501 | });
2502 |
2503 | // Prevent memory leaks in IE
2504 | // Window isn't included so as not to unbind existing unload events
2505 | // More info:
2506 | // - http://isaacschlueter.com/2006/10/msie-memory-leaks/
2507 | if ( window.attachEvent && !window.addEventListener ) {
2508 | window.attachEvent("onunload", function() {
2509 | for ( var id in jQuery.cache ) {
2510 | if ( jQuery.cache[ id ].handle ) {
2511 | // Try/Catch is to handle iframes being unloaded, see #4280
2512 | try {
2513 | jQuery.event.remove( jQuery.cache[ id ].handle.elem );
2514 | } catch(e) {}
2515 | }
2516 | }
2517 | });
2518 | }
2519 | /*!
2520 | * Sizzle CSS Selector Engine - v1.0
2521 | * Copyright 2009, The Dojo Foundation
2522 | * Released under the MIT, BSD, and GPL Licenses.
2523 | * More information: http://sizzlejs.com/
2524 | */
2525 | (function(){
2526 |
2527 | var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,
2528 | done = 0,
2529 | toString = Object.prototype.toString,
2530 | hasDuplicate = false,
2531 | baseHasDuplicate = true;
2532 |
2533 | // Here we check if the JavaScript engine is using some sort of
2534 | // optimization where it does not always call our comparision
2535 | // function. If that is the case, discard the hasDuplicate value.
2536 | // Thus far that includes Google Chrome.
2537 | [0, 0].sort(function(){
2538 | baseHasDuplicate = false;
2539 | return 0;
2540 | });
2541 |
2542 | var Sizzle = function(selector, context, results, seed) {
2543 | results = results || [];
2544 | var origContext = context = context || document;
2545 |
2546 | if ( context.nodeType !== 1 && context.nodeType !== 9 ) {
2547 | return [];
2548 | }
2549 |
2550 | if ( !selector || typeof selector !== "string" ) {
2551 | return results;
2552 | }
2553 |
2554 | var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context),
2555 | soFar = selector;
2556 |
2557 | // Reset the position of the chunker regexp (start from head)
2558 | while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) {
2559 | soFar = m[3];
2560 |
2561 | parts.push( m[1] );
2562 |
2563 | if ( m[2] ) {
2564 | extra = m[3];
2565 | break;
2566 | }
2567 | }
2568 |
2569 | if ( parts.length > 1 && origPOS.exec( selector ) ) {
2570 | if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {
2571 | set = posProcess( parts[0] + parts[1], context );
2572 | } else {
2573 | set = Expr.relative[ parts[0] ] ?
2574 | [ context ] :
2575 | Sizzle( parts.shift(), context );
2576 |
2577 | while ( parts.length ) {
2578 | selector = parts.shift();
2579 |
2580 | if ( Expr.relative[ selector ] ) {
2581 | selector += parts.shift();
2582 | }
2583 |
2584 | set = posProcess( selector, set );
2585 | }
2586 | }
2587 | } else {
2588 | // Take a shortcut and set the context if the root selector is an ID
2589 | // (but not if it'll be faster if the inner selector is an ID)
2590 | if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&
2591 | Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {
2592 | var ret = Sizzle.find( parts.shift(), context, contextXML );
2593 | context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0];
2594 | }
2595 |
2596 | if ( context ) {
2597 | var ret = seed ?
2598 | { expr: parts.pop(), set: makeArray(seed) } :
2599 | Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML );
2600 | set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set;
2601 |
2602 | if ( parts.length > 0 ) {
2603 | checkSet = makeArray(set);
2604 | } else {
2605 | prune = false;
2606 | }
2607 |
2608 | while ( parts.length ) {
2609 | var cur = parts.pop(), pop = cur;
2610 |
2611 | if ( !Expr.relative[ cur ] ) {
2612 | cur = "";
2613 | } else {
2614 | pop = parts.pop();
2615 | }
2616 |
2617 | if ( pop == null ) {
2618 | pop = context;
2619 | }
2620 |
2621 | Expr.relative[ cur ]( checkSet, pop, contextXML );
2622 | }
2623 | } else {
2624 | checkSet = parts = [];
2625 | }
2626 | }
2627 |
2628 | if ( !checkSet ) {
2629 | checkSet = set;
2630 | }
2631 |
2632 | if ( !checkSet ) {
2633 | Sizzle.error( cur || selector );
2634 | }
2635 |
2636 | if ( toString.call(checkSet) === "[object Array]" ) {
2637 | if ( !prune ) {
2638 | results.push.apply( results, checkSet );
2639 | } else if ( context && context.nodeType === 1 ) {
2640 | for ( var i = 0; checkSet[i] != null; i++ ) {
2641 | if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) {
2642 | results.push( set[i] );
2643 | }
2644 | }
2645 | } else {
2646 | for ( var i = 0; checkSet[i] != null; i++ ) {
2647 | if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
2648 | results.push( set[i] );
2649 | }
2650 | }
2651 | }
2652 | } else {
2653 | makeArray( checkSet, results );
2654 | }
2655 |
2656 | if ( extra ) {
2657 | Sizzle( extra, origContext, results, seed );
2658 | Sizzle.uniqueSort( results );
2659 | }
2660 |
2661 | return results;
2662 | };
2663 |
2664 | Sizzle.uniqueSort = function(results){
2665 | if ( sortOrder ) {
2666 | hasDuplicate = baseHasDuplicate;
2667 | results.sort(sortOrder);
2668 |
2669 | if ( hasDuplicate ) {
2670 | for ( var i = 1; i < results.length; i++ ) {
2671 | if ( results[i] === results[i-1] ) {
2672 | results.splice(i--, 1);
2673 | }
2674 | }
2675 | }
2676 | }
2677 |
2678 | return results;
2679 | };
2680 |
2681 | Sizzle.matches = function(expr, set){
2682 | return Sizzle(expr, null, null, set);
2683 | };
2684 |
2685 | Sizzle.find = function(expr, context, isXML){
2686 | var set, match;
2687 |
2688 | if ( !expr ) {
2689 | return [];
2690 | }
2691 |
2692 | for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
2693 | var type = Expr.order[i], match;
2694 |
2695 | if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
2696 | var left = match[1];
2697 | match.splice(1,1);
2698 |
2699 | if ( left.substr( left.length - 1 ) !== "\\" ) {
2700 | match[1] = (match[1] || "").replace(/\\/g, "");
2701 | set = Expr.find[ type ]( match, context, isXML );
2702 | if ( set != null ) {
2703 | expr = expr.replace( Expr.match[ type ], "" );
2704 | break;
2705 | }
2706 | }
2707 | }
2708 | }
2709 |
2710 | if ( !set ) {
2711 | set = context.getElementsByTagName("*");
2712 | }
2713 |
2714 | return {set: set, expr: expr};
2715 | };
2716 |
2717 | Sizzle.filter = function(expr, set, inplace, not){
2718 | var old = expr, result = [], curLoop = set, match, anyFound,
2719 | isXMLFilter = set && set[0] && isXML(set[0]);
2720 |
2721 | while ( expr && set.length ) {
2722 | for ( var type in Expr.filter ) {
2723 | if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {
2724 | var filter = Expr.filter[ type ], found, item, left = match[1];
2725 | anyFound = false;
2726 |
2727 | match.splice(1,1);
2728 |
2729 | if ( left.substr( left.length - 1 ) === "\\" ) {
2730 | continue;
2731 | }
2732 |
2733 | if ( curLoop === result ) {
2734 | result = [];
2735 | }
2736 |
2737 | if ( Expr.preFilter[ type ] ) {
2738 | match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );
2739 |
2740 | if ( !match ) {
2741 | anyFound = found = true;
2742 | } else if ( match === true ) {
2743 | continue;
2744 | }
2745 | }
2746 |
2747 | if ( match ) {
2748 | for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
2749 | if ( item ) {
2750 | found = filter( item, match, i, curLoop );
2751 | var pass = not ^ !!found;
2752 |
2753 | if ( inplace && found != null ) {
2754 | if ( pass ) {
2755 | anyFound = true;
2756 | } else {
2757 | curLoop[i] = false;
2758 | }
2759 | } else if ( pass ) {
2760 | result.push( item );
2761 | anyFound = true;
2762 | }
2763 | }
2764 | }
2765 | }
2766 |
2767 | if ( found !== undefined ) {
2768 | if ( !inplace ) {
2769 | curLoop = result;
2770 | }
2771 |
2772 | expr = expr.replace( Expr.match[ type ], "" );
2773 |
2774 | if ( !anyFound ) {
2775 | return [];
2776 | }
2777 |
2778 | break;
2779 | }
2780 | }
2781 | }
2782 |
2783 | // Improper expression
2784 | if ( expr === old ) {
2785 | if ( anyFound == null ) {
2786 | Sizzle.error( expr );
2787 | } else {
2788 | break;
2789 | }
2790 | }
2791 |
2792 | old = expr;
2793 | }
2794 |
2795 | return curLoop;
2796 | };
2797 |
2798 | Sizzle.error = function( msg ) {
2799 | throw "Syntax error, unrecognized expression: " + msg;
2800 | };
2801 |
2802 | var Expr = Sizzle.selectors = {
2803 | order: [ "ID", "NAME", "TAG" ],
2804 | match: {
2805 | ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
2806 | CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
2807 | NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
2808 | ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
2809 | TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
2810 | CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
2811 | POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
2812 | PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
2813 | },
2814 | leftMatch: {},
2815 | attrMap: {
2816 | "class": "className",
2817 | "for": "htmlFor"
2818 | },
2819 | attrHandle: {
2820 | href: function(elem){
2821 | return elem.getAttribute("href");
2822 | }
2823 | },
2824 | relative: {
2825 | "+": function(checkSet, part){
2826 | var isPartStr = typeof part === "string",
2827 | isTag = isPartStr && !/\W/.test(part),
2828 | isPartStrNotTag = isPartStr && !isTag;
2829 |
2830 | if ( isTag ) {
2831 | part = part.toLowerCase();
2832 | }
2833 |
2834 | for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
2835 | if ( (elem = checkSet[i]) ) {
2836 | while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}
2837 |
2838 | checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?
2839 | elem || false :
2840 | elem === part;
2841 | }
2842 | }
2843 |
2844 | if ( isPartStrNotTag ) {
2845 | Sizzle.filter( part, checkSet, true );
2846 | }
2847 | },
2848 | ">": function(checkSet, part){
2849 | var isPartStr = typeof part === "string";
2850 |
2851 | if ( isPartStr && !/\W/.test(part) ) {
2852 | part = part.toLowerCase();
2853 |
2854 | for ( var i = 0, l = checkSet.length; i < l; i++ ) {
2855 | var elem = checkSet[i];
2856 | if ( elem ) {
2857 | var parent = elem.parentNode;
2858 | checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;
2859 | }
2860 | }
2861 | } else {
2862 | for ( var i = 0, l = checkSet.length; i < l; i++ ) {
2863 | var elem = checkSet[i];
2864 | if ( elem ) {
2865 | checkSet[i] = isPartStr ?
2866 | elem.parentNode :
2867 | elem.parentNode === part;
2868 | }
2869 | }
2870 |
2871 | if ( isPartStr ) {
2872 | Sizzle.filter( part, checkSet, true );
2873 | }
2874 | }
2875 | },
2876 | "": function(checkSet, part, isXML){
2877 | var doneName = done++, checkFn = dirCheck;
2878 |
2879 | if ( typeof part === "string" && !/\W/.test(part) ) {
2880 | var nodeCheck = part = part.toLowerCase();
2881 | checkFn = dirNodeCheck;
2882 | }
2883 |
2884 | checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
2885 | },
2886 | "~": function(checkSet, part, isXML){
2887 | var doneName = done++, checkFn = dirCheck;
2888 |
2889 | if ( typeof part === "string" && !/\W/.test(part) ) {
2890 | var nodeCheck = part = part.toLowerCase();
2891 | checkFn = dirNodeCheck;
2892 | }
2893 |
2894 | checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
2895 | }
2896 | },
2897 | find: {
2898 | ID: function(match, context, isXML){
2899 | if ( typeof context.getElementById !== "undefined" && !isXML ) {
2900 | var m = context.getElementById(match[1]);
2901 | return m ? [m] : [];
2902 | }
2903 | },
2904 | NAME: function(match, context){
2905 | if ( typeof context.getElementsByName !== "undefined" ) {
2906 | var ret = [], results = context.getElementsByName(match[1]);
2907 |
2908 | for ( var i = 0, l = results.length; i < l; i++ ) {
2909 | if ( results[i].getAttribute("name") === match[1] ) {
2910 | ret.push( results[i] );
2911 | }
2912 | }
2913 |
2914 | return ret.length === 0 ? null : ret;
2915 | }
2916 | },
2917 | TAG: function(match, context){
2918 | return context.getElementsByTagName(match[1]);
2919 | }
2920 | },
2921 | preFilter: {
2922 | CLASS: function(match, curLoop, inplace, result, not, isXML){
2923 | match = " " + match[1].replace(/\\/g, "") + " ";
2924 |
2925 | if ( isXML ) {
2926 | return match;
2927 | }
2928 |
2929 | for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
2930 | if ( elem ) {
2931 | if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
2932 | if ( !inplace ) {
2933 | result.push( elem );
2934 | }
2935 | } else if ( inplace ) {
2936 | curLoop[i] = false;
2937 | }
2938 | }
2939 | }
2940 |
2941 | return false;
2942 | },
2943 | ID: function(match){
2944 | return match[1].replace(/\\/g, "");
2945 | },
2946 | TAG: function(match, curLoop){
2947 | return match[1].toLowerCase();
2948 | },
2949 | CHILD: function(match){
2950 | if ( match[1] === "nth" ) {
2951 | // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
2952 | var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
2953 | match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" ||
2954 | !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
2955 |
2956 | // calculate the numbers (first)n+(last) including if they are negative
2957 | match[2] = (test[1] + (test[2] || 1)) - 0;
2958 | match[3] = test[3] - 0;
2959 | }
2960 |
2961 | // TODO: Move to normal caching system
2962 | match[0] = done++;
2963 |
2964 | return match;
2965 | },
2966 | ATTR: function(match, curLoop, inplace, result, not, isXML){
2967 | var name = match[1].replace(/\\/g, "");
2968 |
2969 | if ( !isXML && Expr.attrMap[name] ) {
2970 | match[1] = Expr.attrMap[name];
2971 | }
2972 |
2973 | if ( match[2] === "~=" ) {
2974 | match[4] = " " + match[4] + " ";
2975 | }
2976 |
2977 | return match;
2978 | },
2979 | PSEUDO: function(match, curLoop, inplace, result, not){
2980 | if ( match[1] === "not" ) {
2981 | // If we're dealing with a complex expression, or a simple one
2982 | if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) {
2983 | match[3] = Sizzle(match[3], null, null, curLoop);
2984 | } else {
2985 | var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
2986 | if ( !inplace ) {
2987 | result.push.apply( result, ret );
2988 | }
2989 | return false;
2990 | }
2991 | } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {
2992 | return true;
2993 | }
2994 |
2995 | return match;
2996 | },
2997 | POS: function(match){
2998 | match.unshift( true );
2999 | return match;
3000 | }
3001 | },
3002 | filters: {
3003 | enabled: function(elem){
3004 | return elem.disabled === false && elem.type !== "hidden";
3005 | },
3006 | disabled: function(elem){
3007 | return elem.disabled === true;
3008 | },
3009 | checked: function(elem){
3010 | return elem.checked === true;
3011 | },
3012 | selected: function(elem){
3013 | // Accessing this property makes selected-by-default
3014 | // options in Safari work properly
3015 | elem.parentNode.selectedIndex;
3016 | return elem.selected === true;
3017 | },
3018 | parent: function(elem){
3019 | return !!elem.firstChild;
3020 | },
3021 | empty: function(elem){
3022 | return !elem.firstChild;
3023 | },
3024 | has: function(elem, i, match){
3025 | return !!Sizzle( match[3], elem ).length;
3026 | },
3027 | header: function(elem){
3028 | return /h\d/i.test( elem.nodeName );
3029 | },
3030 | text: function(elem){
3031 | return "text" === elem.type;
3032 | },
3033 | radio: function(elem){
3034 | return "radio" === elem.type;
3035 | },
3036 | checkbox: function(elem){
3037 | return "checkbox" === elem.type;
3038 | },
3039 | file: function(elem){
3040 | return "file" === elem.type;
3041 | },
3042 | password: function(elem){
3043 | return "password" === elem.type;
3044 | },
3045 | submit: function(elem){
3046 | return "submit" === elem.type;
3047 | },
3048 | image: function(elem){
3049 | return "image" === elem.type;
3050 | },
3051 | reset: function(elem){
3052 | return "reset" === elem.type;
3053 | },
3054 | button: function(elem){
3055 | return "button" === elem.type || elem.nodeName.toLowerCase() === "button";
3056 | },
3057 | input: function(elem){
3058 | return /input|select|textarea|button/i.test(elem.nodeName);
3059 | }
3060 | },
3061 | setFilters: {
3062 | first: function(elem, i){
3063 | return i === 0;
3064 | },
3065 | last: function(elem, i, match, array){
3066 | return i === array.length - 1;
3067 | },
3068 | even: function(elem, i){
3069 | return i % 2 === 0;
3070 | },
3071 | odd: function(elem, i){
3072 | return i % 2 === 1;
3073 | },
3074 | lt: function(elem, i, match){
3075 | return i < match[3] - 0;
3076 | },
3077 | gt: function(elem, i, match){
3078 | return i > match[3] - 0;
3079 | },
3080 | nth: function(elem, i, match){
3081 | return match[3] - 0 === i;
3082 | },
3083 | eq: function(elem, i, match){
3084 | return match[3] - 0 === i;
3085 | }
3086 | },
3087 | filter: {
3088 | PSEUDO: function(elem, match, i, array){
3089 | var name = match[1], filter = Expr.filters[ name ];
3090 |
3091 | if ( filter ) {
3092 | return filter( elem, i, match, array );
3093 | } else if ( name === "contains" ) {
3094 | return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0;
3095 | } else if ( name === "not" ) {
3096 | var not = match[3];
3097 |
3098 | for ( var i = 0, l = not.length; i < l; i++ ) {
3099 | if ( not[i] === elem ) {
3100 | return false;
3101 | }
3102 | }
3103 |
3104 | return true;
3105 | } else {
3106 | Sizzle.error( "Syntax error, unrecognized expression: " + name );
3107 | }
3108 | },
3109 | CHILD: function(elem, match){
3110 | var type = match[1], node = elem;
3111 | switch (type) {
3112 | case 'only':
3113 | case 'first':
3114 | while ( (node = node.previousSibling) ) {
3115 | if ( node.nodeType === 1 ) {
3116 | return false;
3117 | }
3118 | }
3119 | if ( type === "first" ) {
3120 | return true;
3121 | }
3122 | node = elem;
3123 | case 'last':
3124 | while ( (node = node.nextSibling) ) {
3125 | if ( node.nodeType === 1 ) {
3126 | return false;
3127 | }
3128 | }
3129 | return true;
3130 | case 'nth':
3131 | var first = match[2], last = match[3];
3132 |
3133 | if ( first === 1 && last === 0 ) {
3134 | return true;
3135 | }
3136 |
3137 | var doneName = match[0],
3138 | parent = elem.parentNode;
3139 |
3140 | if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {
3141 | var count = 0;
3142 | for ( node = parent.firstChild; node; node = node.nextSibling ) {
3143 | if ( node.nodeType === 1 ) {
3144 | node.nodeIndex = ++count;
3145 | }
3146 | }
3147 | parent.sizcache = doneName;
3148 | }
3149 |
3150 | var diff = elem.nodeIndex - last;
3151 | if ( first === 0 ) {
3152 | return diff === 0;
3153 | } else {
3154 | return ( diff % first === 0 && diff / first >= 0 );
3155 | }
3156 | }
3157 | },
3158 | ID: function(elem, match){
3159 | return elem.nodeType === 1 && elem.getAttribute("id") === match;
3160 | },
3161 | TAG: function(elem, match){
3162 | return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;
3163 | },
3164 | CLASS: function(elem, match){
3165 | return (" " + (elem.className || elem.getAttribute("class")) + " ")
3166 | .indexOf( match ) > -1;
3167 | },
3168 | ATTR: function(elem, match){
3169 | var name = match[1],
3170 | result = Expr.attrHandle[ name ] ?
3171 | Expr.attrHandle[ name ]( elem ) :
3172 | elem[ name ] != null ?
3173 | elem[ name ] :
3174 | elem.getAttribute( name ),
3175 | value = result + "",
3176 | type = match[2],
3177 | check = match[4];
3178 |
3179 | return result == null ?
3180 | type === "!=" :
3181 | type === "=" ?
3182 | value === check :
3183 | type === "*=" ?
3184 | value.indexOf(check) >= 0 :
3185 | type === "~=" ?
3186 | (" " + value + " ").indexOf(check) >= 0 :
3187 | !check ?
3188 | value && result !== false :
3189 | type === "!=" ?
3190 | value !== check :
3191 | type === "^=" ?
3192 | value.indexOf(check) === 0 :
3193 | type === "$=" ?
3194 | value.substr(value.length - check.length) === check :
3195 | type === "|=" ?
3196 | value === check || value.substr(0, check.length + 1) === check + "-" :
3197 | false;
3198 | },
3199 | POS: function(elem, match, i, array){
3200 | var name = match[2], filter = Expr.setFilters[ name ];
3201 |
3202 | if ( filter ) {
3203 | return filter( elem, i, match, array );
3204 | }
3205 | }
3206 | }
3207 | };
3208 |
3209 | var origPOS = Expr.match.POS;
3210 |
3211 | for ( var type in Expr.match ) {
3212 | Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source );
3213 | Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){
3214 | return "\\" + (num - 0 + 1);
3215 | }));
3216 | }
3217 |
3218 | var makeArray = function(array, results) {
3219 | array = Array.prototype.slice.call( array, 0 );
3220 |
3221 | if ( results ) {
3222 | results.push.apply( results, array );
3223 | return results;
3224 | }
3225 |
3226 | return array;
3227 | };
3228 |
3229 | // Perform a simple check to determine if the browser is capable of
3230 | // converting a NodeList to an array using builtin methods.
3231 | try {
3232 | Array.prototype.slice.call( document.documentElement.childNodes, 0 );
3233 |
3234 | // Provide a fallback method if it does not work
3235 | } catch(e){
3236 | makeArray = function(array, results) {
3237 | var ret = results || [];
3238 |
3239 | if ( toString.call(array) === "[object Array]" ) {
3240 | Array.prototype.push.apply( ret, array );
3241 | } else {
3242 | if ( typeof array.length === "number" ) {
3243 | for ( var i = 0, l = array.length; i < l; i++ ) {
3244 | ret.push( array[i] );
3245 | }
3246 | } else {
3247 | for ( var i = 0; array[i]; i++ ) {
3248 | ret.push( array[i] );
3249 | }
3250 | }
3251 | }
3252 |
3253 | return ret;
3254 | };
3255 | }
3256 |
3257 | var sortOrder;
3258 |
3259 | if ( document.documentElement.compareDocumentPosition ) {
3260 | sortOrder = function( a, b ) {
3261 | if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {
3262 | if ( a == b ) {
3263 | hasDuplicate = true;
3264 | }
3265 | return a.compareDocumentPosition ? -1 : 1;
3266 | }
3267 |
3268 | var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1;
3269 | if ( ret === 0 ) {
3270 | hasDuplicate = true;
3271 | }
3272 | return ret;
3273 | };
3274 | } else if ( "sourceIndex" in document.documentElement ) {
3275 | sortOrder = function( a, b ) {
3276 | if ( !a.sourceIndex || !b.sourceIndex ) {
3277 | if ( a == b ) {
3278 | hasDuplicate = true;
3279 | }
3280 | return a.sourceIndex ? -1 : 1;
3281 | }
3282 |
3283 | var ret = a.sourceIndex - b.sourceIndex;
3284 | if ( ret === 0 ) {
3285 | hasDuplicate = true;
3286 | }
3287 | return ret;
3288 | };
3289 | } else if ( document.createRange ) {
3290 | sortOrder = function( a, b ) {
3291 | if ( !a.ownerDocument || !b.ownerDocument ) {
3292 | if ( a == b ) {
3293 | hasDuplicate = true;
3294 | }
3295 | return a.ownerDocument ? -1 : 1;
3296 | }
3297 |
3298 | var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange();
3299 | aRange.setStart(a, 0);
3300 | aRange.setEnd(a, 0);
3301 | bRange.setStart(b, 0);
3302 | bRange.setEnd(b, 0);
3303 | var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange);
3304 | if ( ret === 0 ) {
3305 | hasDuplicate = true;
3306 | }
3307 | return ret;
3308 | };
3309 | }
3310 |
3311 | // Utility function for retreiving the text value of an array of DOM nodes
3312 | function getText( elems ) {
3313 | var ret = "", elem;
3314 |
3315 | for ( var i = 0; elems[i]; i++ ) {
3316 | elem = elems[i];
3317 |
3318 | // Get the text from text nodes and CDATA nodes
3319 | if ( elem.nodeType === 3 || elem.nodeType === 4 ) {
3320 | ret += elem.nodeValue;
3321 |
3322 | // Traverse everything else, except comment nodes
3323 | } else if ( elem.nodeType !== 8 ) {
3324 | ret += getText( elem.childNodes );
3325 | }
3326 | }
3327 |
3328 | return ret;
3329 | }
3330 |
3331 | // Check to see if the browser returns elements by name when
3332 | // querying by getElementById (and provide a workaround)
3333 | (function(){
3334 | // We're going to inject a fake input element with a specified name
3335 | var form = document.createElement("div"),
3336 | id = "script" + (new Date).getTime();
3337 | form.innerHTML = "";
3338 |
3339 | // Inject it into the root element, check its status, and remove it quickly
3340 | var root = document.documentElement;
3341 | root.insertBefore( form, root.firstChild );
3342 |
3343 | // The workaround has to do additional checks after a getElementById
3344 | // Which slows things down for other browsers (hence the branching)
3345 | if ( document.getElementById( id ) ) {
3346 | Expr.find.ID = function(match, context, isXML){
3347 | if ( typeof context.getElementById !== "undefined" && !isXML ) {
3348 | var m = context.getElementById(match[1]);
3349 | return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
3350 | }
3351 | };
3352 |
3353 | Expr.filter.ID = function(elem, match){
3354 | var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id");
3355 | return elem.nodeType === 1 && node && node.nodeValue === match;
3356 | };
3357 | }
3358 |
3359 | root.removeChild( form );
3360 | root = form = null; // release memory in IE
3361 | })();
3362 |
3363 | (function(){
3364 | // Check to see if the browser returns only elements
3365 | // when doing getElementsByTagName("*")
3366 |
3367 | // Create a fake element
3368 | var div = document.createElement("div");
3369 | div.appendChild( document.createComment("") );
3370 |
3371 | // Make sure no comments are found
3372 | if ( div.getElementsByTagName("*").length > 0 ) {
3373 | Expr.find.TAG = function(match, context){
3374 | var results = context.getElementsByTagName(match[1]);
3375 |
3376 | // Filter out possible comments
3377 | if ( match[1] === "*" ) {
3378 | var tmp = [];
3379 |
3380 | for ( var i = 0; results[i]; i++ ) {
3381 | if ( results[i].nodeType === 1 ) {
3382 | tmp.push( results[i] );
3383 | }
3384 | }
3385 |
3386 | results = tmp;
3387 | }
3388 |
3389 | return results;
3390 | };
3391 | }
3392 |
3393 | // Check to see if an attribute returns normalized href attributes
3394 | div.innerHTML = "";
3395 | if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
3396 | div.firstChild.getAttribute("href") !== "#" ) {
3397 | Expr.attrHandle.href = function(elem){
3398 | return elem.getAttribute("href", 2);
3399 | };
3400 | }
3401 |
3402 | div = null; // release memory in IE
3403 | })();
3404 |
3405 | if ( document.querySelectorAll ) {
3406 | (function(){
3407 | var oldSizzle = Sizzle, div = document.createElement("div");
3408 | div.innerHTML = "";
3409 |
3410 | // Safari can't handle uppercase or unicode characters when
3411 | // in quirks mode.
3412 | if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) {
3413 | return;
3414 | }
3415 |
3416 | Sizzle = function(query, context, extra, seed){
3417 | context = context || document;
3418 |
3419 | // Only use querySelectorAll on non-XML documents
3420 | // (ID selectors don't work in non-HTML documents)
3421 | if ( !seed && context.nodeType === 9 && !isXML(context) ) {
3422 | try {
3423 | return makeArray( context.querySelectorAll(query), extra );
3424 | } catch(e){}
3425 | }
3426 |
3427 | return oldSizzle(query, context, extra, seed);
3428 | };
3429 |
3430 | for ( var prop in oldSizzle ) {
3431 | Sizzle[ prop ] = oldSizzle[ prop ];
3432 | }
3433 |
3434 | div = null; // release memory in IE
3435 | })();
3436 | }
3437 |
3438 | (function(){
3439 | var div = document.createElement("div");
3440 |
3441 | div.innerHTML = "";
3442 |
3443 | // Opera can't find a second classname (in 9.6)
3444 | // Also, make sure that getElementsByClassName actually exists
3445 | if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) {
3446 | return;
3447 | }
3448 |
3449 | // Safari caches class attributes, doesn't catch changes (in 3.2)
3450 | div.lastChild.className = "e";
3451 |
3452 | if ( div.getElementsByClassName("e").length === 1 ) {
3453 | return;
3454 | }
3455 |
3456 | Expr.order.splice(1, 0, "CLASS");
3457 | Expr.find.CLASS = function(match, context, isXML) {
3458 | if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) {
3459 | return context.getElementsByClassName(match[1]);
3460 | }
3461 | };
3462 |
3463 | div = null; // release memory in IE
3464 | })();
3465 |
3466 | function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
3467 | for ( var i = 0, l = checkSet.length; i < l; i++ ) {
3468 | var elem = checkSet[i];
3469 | if ( elem ) {
3470 | elem = elem[dir];
3471 | var match = false;
3472 |
3473 | while ( elem ) {
3474 | if ( elem.sizcache === doneName ) {
3475 | match = checkSet[elem.sizset];
3476 | break;
3477 | }
3478 |
3479 | if ( elem.nodeType === 1 && !isXML ){
3480 | elem.sizcache = doneName;
3481 | elem.sizset = i;
3482 | }
3483 |
3484 | if ( elem.nodeName.toLowerCase() === cur ) {
3485 | match = elem;
3486 | break;
3487 | }
3488 |
3489 | elem = elem[dir];
3490 | }
3491 |
3492 | checkSet[i] = match;
3493 | }
3494 | }
3495 | }
3496 |
3497 | function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
3498 | for ( var i = 0, l = checkSet.length; i < l; i++ ) {
3499 | var elem = checkSet[i];
3500 | if ( elem ) {
3501 | elem = elem[dir];
3502 | var match = false;
3503 |
3504 | while ( elem ) {
3505 | if ( elem.sizcache === doneName ) {
3506 | match = checkSet[elem.sizset];
3507 | break;
3508 | }
3509 |
3510 | if ( elem.nodeType === 1 ) {
3511 | if ( !isXML ) {
3512 | elem.sizcache = doneName;
3513 | elem.sizset = i;
3514 | }
3515 | if ( typeof cur !== "string" ) {
3516 | if ( elem === cur ) {
3517 | match = true;
3518 | break;
3519 | }
3520 |
3521 | } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
3522 | match = elem;
3523 | break;
3524 | }
3525 | }
3526 |
3527 | elem = elem[dir];
3528 | }
3529 |
3530 | checkSet[i] = match;
3531 | }
3532 | }
3533 | }
3534 |
3535 | var contains = document.compareDocumentPosition ? function(a, b){
3536 | return a.compareDocumentPosition(b) & 16;
3537 | } : function(a, b){
3538 | return a !== b && (a.contains ? a.contains(b) : true);
3539 | };
3540 |
3541 | var isXML = function(elem){
3542 | // documentElement is verified for cases where it doesn't yet exist
3543 | // (such as loading iframes in IE - #4833)
3544 | var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;
3545 | return documentElement ? documentElement.nodeName !== "HTML" : false;
3546 | };
3547 |
3548 | var posProcess = function(selector, context){
3549 | var tmpSet = [], later = "", match,
3550 | root = context.nodeType ? [context] : context;
3551 |
3552 | // Position selectors must be done after the filter
3553 | // And so must :not(positional) so we move all PSEUDOs to the end
3554 | while ( (match = Expr.match.PSEUDO.exec( selector )) ) {
3555 | later += match[0];
3556 | selector = selector.replace( Expr.match.PSEUDO, "" );
3557 | }
3558 |
3559 | selector = Expr.relative[selector] ? selector + "*" : selector;
3560 |
3561 | for ( var i = 0, l = root.length; i < l; i++ ) {
3562 | Sizzle( selector, root[i], tmpSet );
3563 | }
3564 |
3565 | return Sizzle.filter( later, tmpSet );
3566 | };
3567 |
3568 | // EXPOSE
3569 | jQuery.find = Sizzle;
3570 | jQuery.expr = Sizzle.selectors;
3571 | jQuery.expr[":"] = jQuery.expr.filters;
3572 | jQuery.unique = Sizzle.uniqueSort;
3573 | jQuery.getText = getText;
3574 | jQuery.isXMLDoc = isXML;
3575 | jQuery.contains = contains;
3576 |
3577 | return;
3578 |
3579 | window.Sizzle = Sizzle;
3580 |
3581 | })();
3582 | var runtil = /Until$/,
3583 | rparentsprev = /^(?:parents|prevUntil|prevAll)/,
3584 | // Note: This RegExp should be improved, or likely pulled from Sizzle
3585 | rmultiselector = /,/,
3586 | slice = Array.prototype.slice;
3587 |
3588 | // Implement the identical functionality for filter and not
3589 | var winnow = function( elements, qualifier, keep ) {
3590 | if ( jQuery.isFunction( qualifier ) ) {
3591 | return jQuery.grep(elements, function( elem, i ) {
3592 | return !!qualifier.call( elem, i, elem ) === keep;
3593 | });
3594 |
3595 | } else if ( qualifier.nodeType ) {
3596 | return jQuery.grep(elements, function( elem, i ) {
3597 | return (elem === qualifier) === keep;
3598 | });
3599 |
3600 | } else if ( typeof qualifier === "string" ) {
3601 | var filtered = jQuery.grep(elements, function( elem ) {
3602 | return elem.nodeType === 1;
3603 | });
3604 |
3605 | if ( isSimple.test( qualifier ) ) {
3606 | return jQuery.filter(qualifier, filtered, !keep);
3607 | } else {
3608 | qualifier = jQuery.filter( qualifier, filtered );
3609 | }
3610 | }
3611 |
3612 | return jQuery.grep(elements, function( elem, i ) {
3613 | return (jQuery.inArray( elem, qualifier ) >= 0) === keep;
3614 | });
3615 | };
3616 |
3617 | jQuery.fn.extend({
3618 | find: function( selector ) {
3619 | var ret = this.pushStack( "", "find", selector ), length = 0;
3620 |
3621 | for ( var i = 0, l = this.length; i < l; i++ ) {
3622 | length = ret.length;
3623 | jQuery.find( selector, this[i], ret );
3624 |
3625 | if ( i > 0 ) {
3626 | // Make sure that the results are unique
3627 | for ( var n = length; n < ret.length; n++ ) {
3628 | for ( var r = 0; r < length; r++ ) {
3629 | if ( ret[r] === ret[n] ) {
3630 | ret.splice(n--, 1);
3631 | break;
3632 | }
3633 | }
3634 | }
3635 | }
3636 | }
3637 |
3638 | return ret;
3639 | },
3640 |
3641 | has: function( target ) {
3642 | var targets = jQuery( target );
3643 | return this.filter(function() {
3644 | for ( var i = 0, l = targets.length; i < l; i++ ) {
3645 | if ( jQuery.contains( this, targets[i] ) ) {
3646 | return true;
3647 | }
3648 | }
3649 | });
3650 | },
3651 |
3652 | not: function( selector ) {
3653 | return this.pushStack( winnow(this, selector, false), "not", selector);
3654 | },
3655 |
3656 | filter: function( selector ) {
3657 | return this.pushStack( winnow(this, selector, true), "filter", selector );
3658 | },
3659 |
3660 | is: function( selector ) {
3661 | return !!selector && jQuery.filter( selector, this ).length > 0;
3662 | },
3663 |
3664 | closest: function( selectors, context ) {
3665 | if ( jQuery.isArray( selectors ) ) {
3666 | var ret = [], cur = this[0], match, matches = {}, selector;
3667 |
3668 | if ( cur && selectors.length ) {
3669 | for ( var i = 0, l = selectors.length; i < l; i++ ) {
3670 | selector = selectors[i];
3671 |
3672 | if ( !matches[selector] ) {
3673 | matches[selector] = jQuery.expr.match.POS.test( selector ) ?
3674 | jQuery( selector, context || this.context ) :
3675 | selector;
3676 | }
3677 | }
3678 |
3679 | while ( cur && cur.ownerDocument && cur !== context ) {
3680 | for ( selector in matches ) {
3681 | match = matches[selector];
3682 |
3683 | if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {
3684 | ret.push({ selector: selector, elem: cur });
3685 | delete matches[selector];
3686 | }
3687 | }
3688 | cur = cur.parentNode;
3689 | }
3690 | }
3691 |
3692 | return ret;
3693 | }
3694 |
3695 | var pos = jQuery.expr.match.POS.test( selectors ) ?
3696 | jQuery( selectors, context || this.context ) : null;
3697 |
3698 | return this.map(function( i, cur ) {
3699 | while ( cur && cur.ownerDocument && cur !== context ) {
3700 | if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) {
3701 | return cur;
3702 | }
3703 | cur = cur.parentNode;
3704 | }
3705 | return null;
3706 | });
3707 | },
3708 |
3709 | // Determine the position of an element within
3710 | // the matched set of elements
3711 | index: function( elem ) {
3712 | if ( !elem || typeof elem === "string" ) {
3713 | return jQuery.inArray( this[0],
3714 | // If it receives a string, the selector is used
3715 | // If it receives nothing, the siblings are used
3716 | elem ? jQuery( elem ) : this.parent().children() );
3717 | }
3718 | // Locate the position of the desired element
3719 | return jQuery.inArray(
3720 | // If it receives a jQuery object, the first element is used
3721 | elem.jquery ? elem[0] : elem, this );
3722 | },
3723 |
3724 | add: function( selector, context ) {
3725 | var set = typeof selector === "string" ?
3726 | jQuery( selector, context || this.context ) :
3727 | jQuery.makeArray( selector ),
3728 | all = jQuery.merge( this.get(), set );
3729 |
3730 | return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
3731 | all :
3732 | jQuery.unique( all ) );
3733 | },
3734 |
3735 | andSelf: function() {
3736 | return this.add( this.prevObject );
3737 | }
3738 | });
3739 |
3740 | // A painfully simple check to see if an element is disconnected
3741 | // from a document (should be improved, where feasible).
3742 | function isDisconnected( node ) {
3743 | return !node || !node.parentNode || node.parentNode.nodeType === 11;
3744 | }
3745 |
3746 | jQuery.each({
3747 | parent: function( elem ) {
3748 | var parent = elem.parentNode;
3749 | return parent && parent.nodeType !== 11 ? parent : null;
3750 | },
3751 | parents: function( elem ) {
3752 | return jQuery.dir( elem, "parentNode" );
3753 | },
3754 | parentsUntil: function( elem, i, until ) {
3755 | return jQuery.dir( elem, "parentNode", until );
3756 | },
3757 | next: function( elem ) {
3758 | return jQuery.nth( elem, 2, "nextSibling" );
3759 | },
3760 | prev: function( elem ) {
3761 | return jQuery.nth( elem, 2, "previousSibling" );
3762 | },
3763 | nextAll: function( elem ) {
3764 | return jQuery.dir( elem, "nextSibling" );
3765 | },
3766 | prevAll: function( elem ) {
3767 | return jQuery.dir( elem, "previousSibling" );
3768 | },
3769 | nextUntil: function( elem, i, until ) {
3770 | return jQuery.dir( elem, "nextSibling", until );
3771 | },
3772 | prevUntil: function( elem, i, until ) {
3773 | return jQuery.dir( elem, "previousSibling", until );
3774 | },
3775 | siblings: function( elem ) {
3776 | return jQuery.sibling( elem.parentNode.firstChild, elem );
3777 | },
3778 | children: function( elem ) {
3779 | return jQuery.sibling( elem.firstChild );
3780 | },
3781 | contents: function( elem ) {
3782 | return jQuery.nodeName( elem, "iframe" ) ?
3783 | elem.contentDocument || elem.contentWindow.document :
3784 | jQuery.makeArray( elem.childNodes );
3785 | }
3786 | }, function( name, fn ) {
3787 | jQuery.fn[ name ] = function( until, selector ) {
3788 | var ret = jQuery.map( this, fn, until );
3789 |
3790 | if ( !runtil.test( name ) ) {
3791 | selector = until;
3792 | }
3793 |
3794 | if ( selector && typeof selector === "string" ) {
3795 | ret = jQuery.filter( selector, ret );
3796 | }
3797 |
3798 | ret = this.length > 1 ? jQuery.unique( ret ) : ret;
3799 |
3800 | if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
3801 | ret = ret.reverse();
3802 | }
3803 |
3804 | return this.pushStack( ret, name, slice.call(arguments).join(",") );
3805 | };
3806 | });
3807 |
3808 | jQuery.extend({
3809 | filter: function( expr, elems, not ) {
3810 | if ( not ) {
3811 | expr = ":not(" + expr + ")";
3812 | }
3813 |
3814 | return jQuery.find.matches(expr, elems);
3815 | },
3816 |
3817 | dir: function( elem, dir, until ) {
3818 | var matched = [], cur = elem[dir];
3819 | while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
3820 | if ( cur.nodeType === 1 ) {
3821 | matched.push( cur );
3822 | }
3823 | cur = cur[dir];
3824 | }
3825 | return matched;
3826 | },
3827 |
3828 | nth: function( cur, result, dir, elem ) {
3829 | result = result || 1;
3830 | var num = 0;
3831 |
3832 | for ( ; cur; cur = cur[dir] ) {
3833 | if ( cur.nodeType === 1 && ++num === result ) {
3834 | break;
3835 | }
3836 | }
3837 |
3838 | return cur;
3839 | },
3840 |
3841 | sibling: function( n, elem ) {
3842 | var r = [];
3843 |
3844 | for ( ; n; n = n.nextSibling ) {
3845 | if ( n.nodeType === 1 && n !== elem ) {
3846 | r.push( n );
3847 | }
3848 | }
3849 |
3850 | return r;
3851 | }
3852 | });
3853 | var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g,
3854 | rleadingWhitespace = /^\s+/,
3855 | rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g,
3856 | rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,
3857 | rtagName = /<([\w:]+)/,
3858 | rtbody = /" + tag + ">";
3865 | },
3866 | wrapMap = {
3867 | option: [ 1, "" ],
3868 | legend: [ 1, "" ],
3869 | thead: [ 1, "" ],
3870 | tr: [ 2, "" ],
3871 | td: [ 3, "" ],
3872 | col: [ 2, "" ],
3873 | area: [ 1, "" ],
3874 | _default: [ 0, "", "" ]
3875 | };
3876 |
3877 | wrapMap.optgroup = wrapMap.option;
3878 | wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
3879 | wrapMap.th = wrapMap.td;
3880 |
3881 | // IE can't serialize and