vanity 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/CHANGELOG +35 -0
  2. data/README.rdoc +33 -6
  3. data/lib/vanity.rb +13 -7
  4. data/lib/vanity/backport.rb +43 -0
  5. data/lib/vanity/commands/report.rb +13 -3
  6. data/lib/vanity/experiment/ab_test.rb +98 -66
  7. data/lib/vanity/experiment/base.rb +51 -5
  8. data/lib/vanity/metric.rb +213 -0
  9. data/lib/vanity/mock_redis.rb +76 -0
  10. data/lib/vanity/playground.rb +78 -61
  11. data/lib/vanity/rails/dashboard.rb +11 -2
  12. data/lib/vanity/rails/helpers.rb +3 -3
  13. data/lib/vanity/templates/_ab_test.erb +3 -4
  14. data/lib/vanity/templates/_experiment.erb +4 -4
  15. data/lib/vanity/templates/_experiments.erb +2 -2
  16. data/lib/vanity/templates/_metric.erb +9 -0
  17. data/lib/vanity/templates/_metrics.erb +13 -0
  18. data/lib/vanity/templates/_report.erb +14 -3
  19. data/lib/vanity/templates/flot.min.js +1 -0
  20. data/lib/vanity/templates/jquery.min.js +19 -0
  21. data/lib/vanity/templates/vanity.css +16 -4
  22. data/lib/vanity/templates/vanity.js +96 -0
  23. data/test/ab_test_test.rb +159 -96
  24. data/test/experiment_test.rb +99 -18
  25. data/test/experiments/age_and_zipcode.rb +1 -0
  26. data/test/experiments/metrics/cheers.rb +3 -0
  27. data/test/experiments/metrics/signups.rb +2 -0
  28. data/test/experiments/metrics/yawns.rb +3 -0
  29. data/test/experiments/null_abc.rb +1 -0
  30. data/test/metric_test.rb +287 -0
  31. data/test/playground_test.rb +1 -80
  32. data/test/rails_test.rb +9 -6
  33. data/test/test_helper.rb +37 -6
  34. data/vanity.gemspec +1 -1
  35. data/vendor/{redis-0.1 → redis-rb}/LICENSE +0 -0
  36. data/vendor/{redis-0.1 → redis-rb}/README.markdown +0 -0
  37. data/vendor/{redis-0.1 → redis-rb}/Rakefile +0 -0
  38. data/vendor/redis-rb/bench.rb +44 -0
  39. data/vendor/redis-rb/benchmarking/suite.rb +24 -0
  40. data/vendor/redis-rb/benchmarking/worker.rb +71 -0
  41. data/vendor/redis-rb/bin/distredis +33 -0
  42. data/vendor/redis-rb/examples/basic.rb +16 -0
  43. data/vendor/redis-rb/examples/incr-decr.rb +18 -0
  44. data/vendor/redis-rb/examples/list.rb +26 -0
  45. data/vendor/redis-rb/examples/sets.rb +36 -0
  46. data/vendor/{redis-0.1 → redis-rb}/lib/dist_redis.rb +0 -0
  47. data/vendor/{redis-0.1 → redis-rb}/lib/hash_ring.rb +0 -0
  48. data/vendor/{redis-0.1 → redis-rb}/lib/pipeline.rb +0 -2
  49. data/vendor/{redis-0.1 → redis-rb}/lib/redis.rb +25 -7
  50. data/vendor/{redis-0.1 → redis-rb}/lib/redis/raketasks.rb +0 -0
  51. data/vendor/redis-rb/profile.rb +22 -0
  52. data/vendor/redis-rb/redis-rb.gemspec +30 -0
  53. data/vendor/{redis-0.1 → redis-rb}/spec/redis_spec.rb +113 -0
  54. data/vendor/{redis-0.1 → redis-rb}/spec/spec_helper.rb +0 -0
  55. data/vendor/redis-rb/speed.rb +16 -0
  56. data/vendor/{redis-0.1 → redis-rb}/tasks/redis.tasks.rb +5 -1
  57. metadata +37 -14
@@ -1,14 +1,23 @@
1
1
  module Vanity
2
2
  module Rails
3
+ # Step 1: Add a new resource in config/routes.rb:
4
+ # map.vanity "/vanity/:action/:id", :controller=>:vanity
5
+ #
6
+ # Step 2: Create a new experiments controller:
7
+ # class VanityController < ApplicationController
8
+ # include Vanity::Rails::Dashboard
9
+ # end
10
+ #
11
+ # Step 3: Open your browser to http://localhost:3000/vanity
3
12
  module Dashboard
4
13
  def index
5
- render Vanity.template("_report"), content_type: Mime::HTML, layout: true
14
+ render Vanity.template("_report"), :content_type=>Mime::HTML, :layout=>true
6
15
  end
7
16
 
8
17
  def chooses
9
18
  exp = Vanity.playground.experiment(params[:e])
10
19
  exp.chooses(exp.alternatives[params[:a].to_i].value)
11
- render partial: Vanity.template("experiment"), locals: { experiment: exp }
20
+ render :partial=>Vanity.template("experiment"), :locals=>{ :experiment=>exp }
12
21
  end
13
22
  end
14
23
  end
@@ -51,7 +51,7 @@ module Vanity
51
51
  @vanity_identity = object.id
52
52
  elsif response # everyday use
53
53
  @vanity_identity = cookies["vanity_id"] || OpenSSL::Random.random_bytes(16).unpack("H*")[0]
54
- cookies["vanity_id"] = { value: @vanity_identity, expires: 1.month.from_now }
54
+ cookies["vanity_id"] = { :value=>@vanity_identity, :expires=>1.month.from_now }
55
55
  @vanity_identity
56
56
  else # during functional testing
57
57
  @vanity_identity = "test"
@@ -103,8 +103,8 @@ module Vanity
103
103
  # track! :call_to_action
104
104
  # Acccount.create! params[:account]
105
105
  # end
106
- def track!(name, *args)
107
- Vanity.playground.experiment(name).track! *args
106
+ def track!(name)
107
+ Vanity.playground.track! name
108
108
  end
109
109
  end
110
110
  end
@@ -11,13 +11,12 @@
11
11
  <%= "(%d%% better than %s)" % [alt.difference, score.least.name] if alt.difference && alt.difference >= 1 %>
12
12
  </td>
13
13
  <td class="action">
14
- <% if experiment.active? && respond_to?(:chooses_experiments_url) %>
14
+ <% if experiment.active? && respond_to?(:url_for) %>
15
15
  <% if experiment.showing?(alt) %>
16
16
  showing
17
17
  <% else %>
18
- <%= link_to_remote "show", update: "experiment_#{experiment.id}",
19
- url: chooses_experiments_url(e: experiment.id, a: alt.id), method: :post,
20
- html: { class: "button", title: "Show me this alternative from now on" } %>
18
+ <a class="button chooses" title="Show me this alternative from now on" href="#"
19
+ data-id="<%= experiment.id %>" data-url="<%= url_for(:action=>:chooses, :e=>experiment.id, :a=>alt.id) %>">show</a>
21
20
  <% end %>
22
21
  <% end %>
23
22
  </td>
@@ -1,5 +1,5 @@
1
- <h2><%=h experiment.name %> <span class="type">(<%= experiment.class.friendly_name %>)</span></h2>
1
+ <h3><%=h experiment.name %> <span class="type">(<%= experiment.class.friendly_name %>)</span></h3>
2
2
  <%= experiment.description.to_s.split(/\n\s*\n/).map { |para| %{<p class="description">#{h para}</p>} }.join %>
3
- <%= render Vanity.template(experiment.type), experiment: experiment %>
4
- <p class="meta">Started <%= experiment.created_at.strftime("%a, %b %-d") %>
5
- <%= " | Completed #{experiment.completed_at.strftime("%a, %b %-d")}" unless experiment.active? %></p>
3
+ <%= render Vanity.template(experiment.type), :experiment=>experiment %>
4
+ <p class="meta">Started <%= experiment.created_at.strftime("%a, %b %d") %>
5
+ <%= " | Completed #{experiment.completed_at.strftime("%a, %b %d")}" unless experiment.active? %></p>
@@ -1,7 +1,7 @@
1
1
  <ul class="experiments">
2
- <% experiments.sort_by(&:created_at).each do |experiment| %>
2
+ <% experiments.sort_by(&:created_at).reverse.each do |experiment| %>
3
3
  <li class="experiment <%= experiment.type %>" id="experiment_<%=h experiment.id.to_s %>">
4
- <%= render Vanity.template("experiment"), experiment: experiment %>
4
+ <%= render Vanity.template("experiment"), :experiment=>experiment %>
5
5
  </li>
6
6
  <% end %>
7
7
  </ul>
@@ -0,0 +1,9 @@
1
+ <h3><%=h metric.name %></h3>
2
+ <%= simple_format h(Vanity::Metric.description(metric).to_s), :class=>"description" %>
3
+ <% data = Vanity::Metric.data(metric)
4
+ min, max = data.map(&:last).minmax
5
+ js = data.map { |date,value| "[#{date.to_time.to_i * 1000},#{value}]" }.join(",") %>
6
+ <div class="chart"></div>
7
+ <script type="text/javascript">
8
+ $(function () { Vanity.metric("<%= id %>").plot([{ label: "<%=h metric.name %>", data: [<%= js %>] }]); });
9
+ </script>
@@ -0,0 +1,13 @@
1
+ <ul class="metrics">
2
+ <% metrics.sort_by { |id, metric| metric.name }.each do |id, metric| %>
3
+ <li class="metric" id="metric_<%= id %>">
4
+ <%= render Vanity.template("metric"), :id=>id, :metric=>metric %>
5
+ </li>
6
+ <% end %>
7
+ </ul>
8
+ <form id="milestones">
9
+ <% experiments.each do |experiment| %>
10
+ <label><input type="checkbox" name="milestone" data-start="<%= experiment.created_at.to_i %>"
11
+ data-end="<%= (experiment.completed_at || Time.now).to_i %>"><%=h experiment.name %></label>
12
+ <% end %>
13
+ </form>
@@ -1,16 +1,27 @@
1
1
  <html>
2
2
  <head>
3
- <title>Experiments (<%= Time.now %>)</title>
3
+ <title>Vanity Report: <%= Time.now.strftime("%b %d %Y, %I:%M:%P") %></title>
4
4
  <style>
5
5
  .vanity { margin: 2em auto; width: 40em; font-family: "Helvetica Neue", "Helvetica", "Verdana", sans-serif }
6
6
  .vanity h1 { margin: 1em 0; border-bottom: 3px solid #ccc }
7
7
  <%= File.read(Vanity.template("vanity.css")) %>
8
8
  </style>
9
+ <script type="text/javascript"><%= File.read(Vanity.template("jquery.min.js")) %></script>
10
+ <script type="text/javascript"><%= File.read(Vanity.template("flot.min.js")) %></script>
11
+ <script type="text/javascript"><%= File.read(Vanity.template("vanity.js")) %></script>
12
+ <% if respond_to?(:form_authenticity_token) %><script type="text/javascript">document.auth_token = "<%= form_authenticity_token %>"</script><% end %>
9
13
  </head>
10
14
  <body>
11
15
  <div class="vanity">
12
- <h1>Experiments</h1>
13
- <%= render Vanity.template("experiments"), experiments: Vanity.playground.experiments %>
16
+ <% experiments = Vanity.playground.experiments ; unless experiments.empty? %>
17
+ <h2>Experiments</h2>
18
+ <%= render Vanity.template("experiments"), :experiments=>experiments %>
19
+ <% end %>
20
+ <% metrics = Vanity.playground.metrics ; unless metrics.empty? %>
21
+ <h2>Metrics</h2>
22
+ <%= render Vanity.template("metrics"), :metrics=>metrics, :experiments=>experiments %>
23
+ <% end %>
24
+ <p class="footer">Generated by <a href="http://vanity.labnotes.org">Vanity</a></p>
14
25
  </div>
15
26
  </body>
16
27
  </html>
@@ -0,0 +1 @@
1
+ (function(){jQuery.color={};jQuery.color.make=function(G,H,J,I){var A={};A.r=G||0;A.g=H||0;A.b=J||0;A.a=I!=null?I:1;A.add=function(C,D){for(var E=0;E<C.length;++E){A[C.charAt(E)]+=D}return A.normalize()};A.scale=function(C,D){for(var E=0;E<C.length;++E){A[C.charAt(E)]*=D}return A.normalize()};A.toString=function(){if(A.a>=1){return"rgb("+[A.r,A.g,A.b].join(",")+")"}else{return"rgba("+[A.r,A.g,A.b,A.a].join(",")+")"}};A.normalize=function(){function C(E,D,F){return D<E?E:(D>F?F:D)}A.r=C(0,parseInt(A.r),255);A.g=C(0,parseInt(A.g),255);A.b=C(0,parseInt(A.b),255);A.a=C(0,A.a,1);return A};A.clone=function(){return jQuery.color.make(A.r,A.b,A.g,A.a)};return A.normalize()};jQuery.color.extract=function(E,F){var A;do{A=E.css(F).toLowerCase();if(A!=""&&A!="transparent"){break}E=E.parent()}while(!jQuery.nodeName(E.get(0),"body"));if(A=="rgba(0, 0, 0, 0)"){A="transparent"}return jQuery.color.parse(A)};jQuery.color.parse=function(A){var F,H=jQuery.color.make;if(F=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(A)){return H(parseInt(F[1],10),parseInt(F[2],10),parseInt(F[3],10))}if(F=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(A)){return H(parseInt(F[1],10),parseInt(F[2],10),parseInt(F[3],10),parseFloat(F[4]))}if(F=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(A)){return H(parseFloat(F[1])*2.55,parseFloat(F[2])*2.55,parseFloat(F[3])*2.55)}if(F=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(A)){return H(parseFloat(F[1])*2.55,parseFloat(F[2])*2.55,parseFloat(F[3])*2.55,parseFloat(F[4]))}if(F=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(A)){return H(parseInt(F[1],16),parseInt(F[2],16),parseInt(F[3],16))}if(F=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(A)){return H(parseInt(F[1]+F[1],16),parseInt(F[2]+F[2],16),parseInt(F[3]+F[3],16))}var G=jQuery.trim(A).toLowerCase();if(G=="transparent"){return H(255,255,255,0)}else{F=B[G];return H(F[0],F[1],F[2])}};var B={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})();(function(C){function B(l,W,X,E){var O=[],g={colors:["#edc240","#afd8f8","#cb4b4b","#4da74d","#9440ed"],legend:{show:true,noColumns:1,labelFormatter:null,labelBoxBorderColor:"#ccc",container:null,position:"ne",margin:5,backgroundColor:null,backgroundOpacity:0.85},xaxis:{mode:null,transform:null,inverseTransform:null,min:null,max:null,autoscaleMargin:null,ticks:null,tickFormatter:null,labelWidth:null,labelHeight:null,tickDecimals:null,tickSize:null,minTickSize:null,monthNames:null,timeformat:null,twelveHourClock:false},yaxis:{autoscaleMargin:0.02},x2axis:{autoscaleMargin:null},y2axis:{autoscaleMargin:0.02},series:{points:{show:false,radius:3,lineWidth:2,fill:true,fillColor:"#ffffff"},lines:{lineWidth:2,fill:false,fillColor:null,steps:false},bars:{show:false,lineWidth:2,barWidth:1,fill:true,fillColor:null,align:"left",horizontal:false},shadowSize:3},grid:{show:true,aboveData:false,color:"#545454",backgroundColor:null,tickColor:"rgba(0,0,0,0.15)",labelMargin:5,borderWidth:2,borderColor:null,markings:null,markingsColor:"#f4f4f4",markingsLineWidth:2,clickable:false,hoverable:false,autoHighlight:true,mouseActiveRadius:10},hooks:{}},P=null,AC=null,AD=null,Y=null,AJ=null,s={xaxis:{},yaxis:{},x2axis:{},y2axis:{}},e={left:0,right:0,top:0,bottom:0},y=0,Q=0,I=0,t=0,L={processOptions:[],processRawData:[],processDatapoints:[],draw:[],bindEvents:[],drawOverlay:[]},G=this;G.setData=f;G.setupGrid=k;G.draw=AH;G.getPlaceholder=function(){return l};G.getCanvas=function(){return P};G.getPlotOffset=function(){return e};G.width=function(){return I};G.height=function(){return t};G.offset=function(){var AK=AD.offset();AK.left+=e.left;AK.top+=e.top;return AK};G.getData=function(){return O};G.getAxes=function(){return s};G.getOptions=function(){return g};G.highlight=AE;G.unhighlight=x;G.triggerRedrawOverlay=q;G.pointOffset=function(AK){return{left:parseInt(T(AK,"xaxis").p2c(+AK.x)+e.left),top:parseInt(T(AK,"yaxis").p2c(+AK.y)+e.top)}};G.hooks=L;b(G);r(X);c();f(W);k();AH();AG();function Z(AM,AK){AK=[G].concat(AK);for(var AL=0;AL<AM.length;++AL){AM[AL].apply(this,AK)}}function b(){for(var AK=0;AK<E.length;++AK){var AL=E[AK];AL.init(G);if(AL.options){C.extend(true,g,AL.options)}}}function r(AK){C.extend(true,g,AK);if(g.grid.borderColor==null){g.grid.borderColor=g.grid.color}if(g.xaxis.noTicks&&g.xaxis.ticks==null){g.xaxis.ticks=g.xaxis.noTicks}if(g.yaxis.noTicks&&g.yaxis.ticks==null){g.yaxis.ticks=g.yaxis.noTicks}if(g.grid.coloredAreas){g.grid.markings=g.grid.coloredAreas}if(g.grid.coloredAreasColor){g.grid.markingsColor=g.grid.coloredAreasColor}if(g.lines){C.extend(true,g.series.lines,g.lines)}if(g.points){C.extend(true,g.series.points,g.points)}if(g.bars){C.extend(true,g.series.bars,g.bars)}if(g.shadowSize){g.series.shadowSize=g.shadowSize}for(var AL in L){if(g.hooks[AL]&&g.hooks[AL].length){L[AL]=L[AL].concat(g.hooks[AL])}}Z(L.processOptions,[g])}function f(AK){O=M(AK);U();m()}function M(AN){var AL=[];for(var AK=0;AK<AN.length;++AK){var AM=C.extend(true,{},g.series);if(AN[AK].data){AM.data=AN[AK].data;delete AN[AK].data;C.extend(true,AM,AN[AK]);AN[AK].data=AM.data}else{AM.data=AN[AK]}AL.push(AM)}return AL}function T(AM,AK){var AL=AM[AK];if(!AL||AL==1){return s[AK]}if(typeof AL=="number"){return s[AK.charAt(0)+AL+AK.slice(1)]}return AL}function U(){var AP;var AV=O.length,AK=[],AN=[];for(AP=0;AP<O.length;++AP){var AS=O[AP].color;if(AS!=null){--AV;if(typeof AS=="number"){AN.push(AS)}else{AK.push(C.color.parse(O[AP].color))}}}for(AP=0;AP<AN.length;++AP){AV=Math.max(AV,AN[AP]+1)}var AL=[],AO=0;AP=0;while(AL.length<AV){var AR;if(g.colors.length==AP){AR=C.color.make(100,100,100)}else{AR=C.color.parse(g.colors[AP])}var AM=AO%2==1?-1:1;AR.scale("rgb",1+AM*Math.ceil(AO/2)*0.2);AL.push(AR);++AP;if(AP>=g.colors.length){AP=0;++AO}}var AQ=0,AW;for(AP=0;AP<O.length;++AP){AW=O[AP];if(AW.color==null){AW.color=AL[AQ].toString();++AQ}else{if(typeof AW.color=="number"){AW.color=AL[AW.color].toString()}}if(AW.lines.show==null){var AU,AT=true;for(AU in AW){if(AW[AU].show){AT=false;break}}if(AT){AW.lines.show=true}}AW.xaxis=T(AW,"xaxis");AW.yaxis=T(AW,"yaxis")}}function m(){var AW=Number.POSITIVE_INFINITY,AQ=Number.NEGATIVE_INFINITY,Ac,Aa,AZ,AV,AL,AR,Ab,AX,AP,AO,AK,Ai,Af,AT;for(AK in s){s[AK].datamin=AW;s[AK].datamax=AQ;s[AK].used=false}function AN(Al,Ak,Aj){if(Ak<Al.datamin){Al.datamin=Ak}if(Aj>Al.datamax){Al.datamax=Aj}}for(Ac=0;Ac<O.length;++Ac){AR=O[Ac];AR.datapoints={points:[]};Z(L.processRawData,[AR,AR.data,AR.datapoints])}for(Ac=0;Ac<O.length;++Ac){AR=O[Ac];var Ah=AR.data,Ae=AR.datapoints.format;if(!Ae){Ae=[];Ae.push({x:true,number:true,required:true});Ae.push({y:true,number:true,required:true});if(AR.bars.show){Ae.push({y:true,number:true,required:false,defaultValue:0})}AR.datapoints.format=Ae}if(AR.datapoints.pointsize!=null){continue}if(AR.datapoints.pointsize==null){AR.datapoints.pointsize=Ae.length}AX=AR.datapoints.pointsize;Ab=AR.datapoints.points;insertSteps=AR.lines.show&&AR.lines.steps;AR.xaxis.used=AR.yaxis.used=true;for(Aa=AZ=0;Aa<Ah.length;++Aa,AZ+=AX){AT=Ah[Aa];var AM=AT==null;if(!AM){for(AV=0;AV<AX;++AV){Ai=AT[AV];Af=Ae[AV];if(Af){if(Af.number&&Ai!=null){Ai=+Ai;if(isNaN(Ai)){Ai=null}}if(Ai==null){if(Af.required){AM=true}if(Af.defaultValue!=null){Ai=Af.defaultValue}}}Ab[AZ+AV]=Ai}}if(AM){for(AV=0;AV<AX;++AV){Ai=Ab[AZ+AV];if(Ai!=null){Af=Ae[AV];if(Af.x){AN(AR.xaxis,Ai,Ai)}if(Af.y){AN(AR.yaxis,Ai,Ai)}}Ab[AZ+AV]=null}}else{if(insertSteps&&AZ>0&&Ab[AZ-AX]!=null&&Ab[AZ-AX]!=Ab[AZ]&&Ab[AZ-AX+1]!=Ab[AZ+1]){for(AV=0;AV<AX;++AV){Ab[AZ+AX+AV]=Ab[AZ+AV]}Ab[AZ+1]=Ab[AZ-AX+1];AZ+=AX}}}}for(Ac=0;Ac<O.length;++Ac){AR=O[Ac];Z(L.processDatapoints,[AR,AR.datapoints])}for(Ac=0;Ac<O.length;++Ac){AR=O[Ac];Ab=AR.datapoints.points,AX=AR.datapoints.pointsize;var AS=AW,AY=AW,AU=AQ,Ad=AQ;for(Aa=0;Aa<Ab.length;Aa+=AX){if(Ab[Aa]==null){continue}for(AV=0;AV<AX;++AV){Ai=Ab[Aa+AV];Af=Ae[AV];if(!Af){continue}if(Af.x){if(Ai<AS){AS=Ai}if(Ai>AU){AU=Ai}}if(Af.y){if(Ai<AY){AY=Ai}if(Ai>Ad){Ad=Ai}}}}if(AR.bars.show){var Ag=AR.bars.align=="left"?0:-AR.bars.barWidth/2;if(AR.bars.horizontal){AY+=Ag;Ad+=Ag+AR.bars.barWidth}else{AS+=Ag;AU+=Ag+AR.bars.barWidth}}AN(AR.xaxis,AS,AU);AN(AR.yaxis,AY,Ad)}for(AK in s){if(s[AK].datamin==AW){s[AK].datamin=null}if(s[AK].datamax==AQ){s[AK].datamax=null}}}function c(){function AK(AM,AL){var AN=document.createElement("canvas");AN.width=AM;AN.height=AL;if(C.browser.msie){AN=window.G_vmlCanvasManager.initElement(AN)}return AN}y=l.width();Q=l.height();l.html("");if(l.css("position")=="static"){l.css("position","relative")}if(y<=0||Q<=0){throw"Invalid dimensions for plot, width = "+y+", height = "+Q}if(C.browser.msie){window.G_vmlCanvasManager.init_(document)}P=C(AK(y,Q)).appendTo(l).get(0);Y=P.getContext("2d");AC=C(AK(y,Q)).css({position:"absolute",left:0,top:0}).appendTo(l).get(0);AJ=AC.getContext("2d");AJ.stroke()}function AG(){AD=C([AC,P]);if(g.grid.hoverable){AD.mousemove(D)}if(g.grid.clickable){AD.click(d)}Z(L.bindEvents,[AD])}function k(){function AL(AT,AU){function AP(AV){return AV}var AS,AO,AQ=AU.transform||AP,AR=AU.inverseTransform;if(AT==s.xaxis||AT==s.x2axis){AS=AT.scale=I/(AQ(AT.max)-AQ(AT.min));AO=AQ(AT.min);if(AQ==AP){AT.p2c=function(AV){return(AV-AO)*AS}}else{AT.p2c=function(AV){return(AQ(AV)-AO)*AS}}if(!AR){AT.c2p=function(AV){return AO+AV/AS}}else{AT.c2p=function(AV){return AR(AO+AV/AS)}}}else{AS=AT.scale=t/(AQ(AT.max)-AQ(AT.min));AO=AQ(AT.max);if(AQ==AP){AT.p2c=function(AV){return(AO-AV)*AS}}else{AT.p2c=function(AV){return(AO-AQ(AV))*AS}}if(!AR){AT.c2p=function(AV){return AO-AV/AS}}else{AT.c2p=function(AV){return AR(AO-AV/AS)}}}}function AN(AR,AT){var AQ,AS=[],AP;AR.labelWidth=AT.labelWidth;AR.labelHeight=AT.labelHeight;if(AR==s.xaxis||AR==s.x2axis){if(AR.labelWidth==null){AR.labelWidth=y/(AR.ticks.length>0?AR.ticks.length:1)}if(AR.labelHeight==null){AS=[];for(AQ=0;AQ<AR.ticks.length;++AQ){AP=AR.ticks[AQ].label;if(AP){AS.push('<div class="tickLabel" style="float:left;width:'+AR.labelWidth+'px">'+AP+"</div>")}}if(AS.length>0){var AO=C('<div style="position:absolute;top:-10000px;width:10000px;font-size:smaller">'+AS.join("")+'<div style="clear:left"></div></div>').appendTo(l);AR.labelHeight=AO.height();AO.remove()}}}else{if(AR.labelWidth==null||AR.labelHeight==null){for(AQ=0;AQ<AR.ticks.length;++AQ){AP=AR.ticks[AQ].label;if(AP){AS.push('<div class="tickLabel">'+AP+"</div>")}}if(AS.length>0){var AO=C('<div style="position:absolute;top:-10000px;font-size:smaller">'+AS.join("")+"</div>").appendTo(l);if(AR.labelWidth==null){AR.labelWidth=AO.width()}if(AR.labelHeight==null){AR.labelHeight=AO.find("div").height()}AO.remove()}}}if(AR.labelWidth==null){AR.labelWidth=0}if(AR.labelHeight==null){AR.labelHeight=0}}function AM(){var AP=g.grid.borderWidth;for(i=0;i<O.length;++i){AP=Math.max(AP,2*(O[i].points.radius+O[i].points.lineWidth/2))}e.left=e.right=e.top=e.bottom=AP;var AO=g.grid.labelMargin+g.grid.borderWidth;if(s.xaxis.labelHeight>0){e.bottom=Math.max(AP,s.xaxis.labelHeight+AO)}if(s.yaxis.labelWidth>0){e.left=Math.max(AP,s.yaxis.labelWidth+AO)}if(s.x2axis.labelHeight>0){e.top=Math.max(AP,s.x2axis.labelHeight+AO)}if(s.y2axis.labelWidth>0){e.right=Math.max(AP,s.y2axis.labelWidth+AO)}I=y-e.left-e.right;t=Q-e.bottom-e.top}var AK;for(AK in s){K(s[AK],g[AK])}if(g.grid.show){for(AK in s){F(s[AK],g[AK]);p(s[AK],g[AK]);AN(s[AK],g[AK])}AM()}else{e.left=e.right=e.top=e.bottom=0;I=y;t=Q}for(AK in s){AL(s[AK],g[AK])}if(g.grid.show){h()}AI()}function K(AN,AQ){var AM=+(AQ.min!=null?AQ.min:AN.datamin),AK=+(AQ.max!=null?AQ.max:AN.datamax),AP=AK-AM;if(AP==0){var AL=AK==0?1:0.01;if(AQ.min==null){AM-=AL}if(AQ.max==null||AQ.min!=null){AK+=AL}}else{var AO=AQ.autoscaleMargin;if(AO!=null){if(AQ.min==null){AM-=AP*AO;if(AM<0&&AN.datamin!=null&&AN.datamin>=0){AM=0}}if(AQ.max==null){AK+=AP*AO;if(AK>0&&AN.datamax!=null&&AN.datamax<=0){AK=0}}}}AN.min=AM;AN.max=AK}function F(AP,AS){var AO;if(typeof AS.ticks=="number"&&AS.ticks>0){AO=AS.ticks}else{if(AP==s.xaxis||AP==s.x2axis){AO=0.3*Math.sqrt(y)}else{AO=0.3*Math.sqrt(Q)}}var AX=(AP.max-AP.min)/AO,AZ,AT,AV,AW,AR,AM,AL;if(AS.mode=="time"){var AU={second:1000,minute:60*1000,hour:60*60*1000,day:24*60*60*1000,month:30*24*60*60*1000,year:365.2425*24*60*60*1000};var AY=[[1,"second"],[2,"second"],[5,"second"],[10,"second"],[30,"second"],[1,"minute"],[2,"minute"],[5,"minute"],[10,"minute"],[30,"minute"],[1,"hour"],[2,"hour"],[4,"hour"],[8,"hour"],[12,"hour"],[1,"day"],[2,"day"],[3,"day"],[0.25,"month"],[0.5,"month"],[1,"month"],[2,"month"],[3,"month"],[6,"month"],[1,"year"]];var AN=0;if(AS.minTickSize!=null){if(typeof AS.tickSize=="number"){AN=AS.tickSize}else{AN=AS.minTickSize[0]*AU[AS.minTickSize[1]]}}for(AR=0;AR<AY.length-1;++AR){if(AX<(AY[AR][0]*AU[AY[AR][1]]+AY[AR+1][0]*AU[AY[AR+1][1]])/2&&AY[AR][0]*AU[AY[AR][1]]>=AN){break}}AZ=AY[AR][0];AV=AY[AR][1];if(AV=="year"){AM=Math.pow(10,Math.floor(Math.log(AX/AU.year)/Math.LN10));AL=(AX/AU.year)/AM;if(AL<1.5){AZ=1}else{if(AL<3){AZ=2}else{if(AL<7.5){AZ=5}else{AZ=10}}}AZ*=AM}if(AS.tickSize){AZ=AS.tickSize[0];AV=AS.tickSize[1]}AT=function(Ac){var Ah=[],Af=Ac.tickSize[0],Ai=Ac.tickSize[1],Ag=new Date(Ac.min);var Ab=Af*AU[Ai];if(Ai=="second"){Ag.setUTCSeconds(A(Ag.getUTCSeconds(),Af))}if(Ai=="minute"){Ag.setUTCMinutes(A(Ag.getUTCMinutes(),Af))}if(Ai=="hour"){Ag.setUTCHours(A(Ag.getUTCHours(),Af))}if(Ai=="month"){Ag.setUTCMonth(A(Ag.getUTCMonth(),Af))}if(Ai=="year"){Ag.setUTCFullYear(A(Ag.getUTCFullYear(),Af))}Ag.setUTCMilliseconds(0);if(Ab>=AU.minute){Ag.setUTCSeconds(0)}if(Ab>=AU.hour){Ag.setUTCMinutes(0)}if(Ab>=AU.day){Ag.setUTCHours(0)}if(Ab>=AU.day*4){Ag.setUTCDate(1)}if(Ab>=AU.year){Ag.setUTCMonth(0)}var Ak=0,Aj=Number.NaN,Ad;do{Ad=Aj;Aj=Ag.getTime();Ah.push({v:Aj,label:Ac.tickFormatter(Aj,Ac)});if(Ai=="month"){if(Af<1){Ag.setUTCDate(1);var Aa=Ag.getTime();Ag.setUTCMonth(Ag.getUTCMonth()+1);var Ae=Ag.getTime();Ag.setTime(Aj+Ak*AU.hour+(Ae-Aa)*Af);Ak=Ag.getUTCHours();Ag.setUTCHours(0)}else{Ag.setUTCMonth(Ag.getUTCMonth()+Af)}}else{if(Ai=="year"){Ag.setUTCFullYear(Ag.getUTCFullYear()+Af)}else{Ag.setTime(Aj+Ab)}}}while(Aj<Ac.max&&Aj!=Ad);return Ah};AW=function(Aa,Ad){var Af=new Date(Aa);if(AS.timeformat!=null){return C.plot.formatDate(Af,AS.timeformat,AS.monthNames)}var Ab=Ad.tickSize[0]*AU[Ad.tickSize[1]];var Ac=Ad.max-Ad.min;var Ae=(AS.twelveHourClock)?" %p":"";if(Ab<AU.minute){fmt="%h:%M:%S"+Ae}else{if(Ab<AU.day){if(Ac<2*AU.day){fmt="%h:%M"+Ae}else{fmt="%b %d %h:%M"+Ae}}else{if(Ab<AU.month){fmt="%b %d"}else{if(Ab<AU.year){if(Ac<AU.year){fmt="%b"}else{fmt="%b %y"}}else{fmt="%y"}}}}return C.plot.formatDate(Af,fmt,AS.monthNames)}}else{var AK=AS.tickDecimals;var AQ=-Math.floor(Math.log(AX)/Math.LN10);if(AK!=null&&AQ>AK){AQ=AK}AM=Math.pow(10,-AQ);AL=AX/AM;if(AL<1.5){AZ=1}else{if(AL<3){AZ=2;if(AL>2.25&&(AK==null||AQ+1<=AK)){AZ=2.5;++AQ}}else{if(AL<7.5){AZ=5}else{AZ=10}}}AZ*=AM;if(AS.minTickSize!=null&&AZ<AS.minTickSize){AZ=AS.minTickSize}if(AS.tickSize!=null){AZ=AS.tickSize}AP.tickDecimals=Math.max(0,(AK!=null)?AK:AQ);AT=function(Ac){var Ae=[];var Af=A(Ac.min,Ac.tickSize),Ab=0,Aa=Number.NaN,Ad;do{Ad=Aa;Aa=Af+Ab*Ac.tickSize;Ae.push({v:Aa,label:Ac.tickFormatter(Aa,Ac)});++Ab}while(Aa<Ac.max&&Aa!=Ad);return Ae};AW=function(Aa,Ab){return Aa.toFixed(Ab.tickDecimals)}}AP.tickSize=AV?[AZ,AV]:AZ;AP.tickGenerator=AT;if(C.isFunction(AS.tickFormatter)){AP.tickFormatter=function(Aa,Ab){return""+AS.tickFormatter(Aa,Ab)}}else{AP.tickFormatter=AW}}function p(AO,AQ){AO.ticks=[];if(!AO.used){return }if(AQ.ticks==null){AO.ticks=AO.tickGenerator(AO)}else{if(typeof AQ.ticks=="number"){if(AQ.ticks>0){AO.ticks=AO.tickGenerator(AO)}}else{if(AQ.ticks){var AP=AQ.ticks;if(C.isFunction(AP)){AP=AP({min:AO.min,max:AO.max})}var AN,AK;for(AN=0;AN<AP.length;++AN){var AL=null;var AM=AP[AN];if(typeof AM=="object"){AK=AM[0];if(AM.length>1){AL=AM[1]}}else{AK=AM}if(AL==null){AL=AO.tickFormatter(AK,AO)}AO.ticks[AN]={v:AK,label:AL}}}}}if(AQ.autoscaleMargin!=null&&AO.ticks.length>0){if(AQ.min==null){AO.min=Math.min(AO.min,AO.ticks[0].v)}if(AQ.max==null&&AO.ticks.length>1){AO.max=Math.max(AO.max,AO.ticks[AO.ticks.length-1].v)}}}function AH(){Y.clearRect(0,0,y,Q);var AL=g.grid;if(AL.show&&!AL.aboveData){S()}for(var AK=0;AK<O.length;++AK){AA(O[AK])}Z(L.draw,[Y]);if(AL.show&&AL.aboveData){S()}}function N(AL,AR){var AO=AR+"axis",AK=AR+"2axis",AN,AQ,AP,AM;if(AL[AO]){AN=s[AO];AQ=AL[AO].from;AP=AL[AO].to}else{if(AL[AK]){AN=s[AK];AQ=AL[AK].from;AP=AL[AK].to}else{AN=s[AO];AQ=AL[AR+"1"];AP=AL[AR+"2"]}}if(AQ!=null&&AP!=null&&AQ>AP){return{from:AP,to:AQ,axis:AN}}return{from:AQ,to:AP,axis:AN}}function S(){var AO;Y.save();Y.translate(e.left,e.top);if(g.grid.backgroundColor){Y.fillStyle=R(g.grid.backgroundColor,t,0,"rgba(255, 255, 255, 0)");Y.fillRect(0,0,I,t)}var AL=g.grid.markings;if(AL){if(C.isFunction(AL)){AL=AL({xmin:s.xaxis.min,xmax:s.xaxis.max,ymin:s.yaxis.min,ymax:s.yaxis.max,xaxis:s.xaxis,yaxis:s.yaxis,x2axis:s.x2axis,y2axis:s.y2axis})}for(AO=0;AO<AL.length;++AO){var AK=AL[AO],AQ=N(AK,"x"),AN=N(AK,"y");if(AQ.from==null){AQ.from=AQ.axis.min}if(AQ.to==null){AQ.to=AQ.axis.max}if(AN.from==null){AN.from=AN.axis.min}if(AN.to==null){AN.to=AN.axis.max}if(AQ.to<AQ.axis.min||AQ.from>AQ.axis.max||AN.to<AN.axis.min||AN.from>AN.axis.max){continue}AQ.from=Math.max(AQ.from,AQ.axis.min);AQ.to=Math.min(AQ.to,AQ.axis.max);AN.from=Math.max(AN.from,AN.axis.min);AN.to=Math.min(AN.to,AN.axis.max);if(AQ.from==AQ.to&&AN.from==AN.to){continue}AQ.from=AQ.axis.p2c(AQ.from);AQ.to=AQ.axis.p2c(AQ.to);AN.from=AN.axis.p2c(AN.from);AN.to=AN.axis.p2c(AN.to);if(AQ.from==AQ.to||AN.from==AN.to){Y.beginPath();Y.strokeStyle=AK.color||g.grid.markingsColor;Y.lineWidth=AK.lineWidth||g.grid.markingsLineWidth;Y.moveTo(AQ.from,AN.from);Y.lineTo(AQ.to,AN.to);Y.stroke()}else{Y.fillStyle=AK.color||g.grid.markingsColor;Y.fillRect(AQ.from,AN.to,AQ.to-AQ.from,AN.from-AN.to)}}}Y.lineWidth=1;Y.strokeStyle=g.grid.tickColor;Y.beginPath();var AM,AP=s.xaxis;for(AO=0;AO<AP.ticks.length;++AO){AM=AP.ticks[AO].v;if(AM<=AP.min||AM>=s.xaxis.max){continue}Y.moveTo(Math.floor(AP.p2c(AM))+Y.lineWidth/2,0);Y.lineTo(Math.floor(AP.p2c(AM))+Y.lineWidth/2,t)}AP=s.yaxis;for(AO=0;AO<AP.ticks.length;++AO){AM=AP.ticks[AO].v;if(AM<=AP.min||AM>=AP.max){continue}Y.moveTo(0,Math.floor(AP.p2c(AM))+Y.lineWidth/2);Y.lineTo(I,Math.floor(AP.p2c(AM))+Y.lineWidth/2)}AP=s.x2axis;for(AO=0;AO<AP.ticks.length;++AO){AM=AP.ticks[AO].v;if(AM<=AP.min||AM>=AP.max){continue}Y.moveTo(Math.floor(AP.p2c(AM))+Y.lineWidth/2,-5);Y.lineTo(Math.floor(AP.p2c(AM))+Y.lineWidth/2,5)}AP=s.y2axis;for(AO=0;AO<AP.ticks.length;++AO){AM=AP.ticks[AO].v;if(AM<=AP.min||AM>=AP.max){continue}Y.moveTo(I-5,Math.floor(AP.p2c(AM))+Y.lineWidth/2);Y.lineTo(I+5,Math.floor(AP.p2c(AM))+Y.lineWidth/2)}Y.stroke();if(g.grid.borderWidth){var AR=g.grid.borderWidth;Y.lineWidth=AR;Y.strokeStyle=g.grid.borderColor;Y.strokeRect(-AR/2,-AR/2,I+AR,t+AR)}Y.restore()}function h(){l.find(".tickLabels").remove();var AK=['<div class="tickLabels" style="font-size:smaller;color:'+g.grid.color+'">'];function AM(AP,AQ){for(var AO=0;AO<AP.ticks.length;++AO){var AN=AP.ticks[AO];if(!AN.label||AN.v<AP.min||AN.v>AP.max){continue}AK.push(AQ(AN,AP))}}var AL=g.grid.labelMargin+g.grid.borderWidth;AM(s.xaxis,function(AN,AO){return'<div style="position:absolute;top:'+(e.top+t+AL)+"px;left:"+Math.round(e.left+AO.p2c(AN.v)-AO.labelWidth/2)+"px;width:"+AO.labelWidth+'px;text-align:center" class="tickLabel">'+AN.label+"</div>"});AM(s.yaxis,function(AN,AO){return'<div style="position:absolute;top:'+Math.round(e.top+AO.p2c(AN.v)-AO.labelHeight/2)+"px;right:"+(e.right+I+AL)+"px;width:"+AO.labelWidth+'px;text-align:right" class="tickLabel">'+AN.label+"</div>"});AM(s.x2axis,function(AN,AO){return'<div style="position:absolute;bottom:'+(e.bottom+t+AL)+"px;left:"+Math.round(e.left+AO.p2c(AN.v)-AO.labelWidth/2)+"px;width:"+AO.labelWidth+'px;text-align:center" class="tickLabel">'+AN.label+"</div>"});AM(s.y2axis,function(AN,AO){return'<div style="position:absolute;top:'+Math.round(e.top+AO.p2c(AN.v)-AO.labelHeight/2)+"px;left:"+(e.left+I+AL)+"px;width:"+AO.labelWidth+'px;text-align:left" class="tickLabel">'+AN.label+"</div>"});AK.push("</div>");l.append(AK.join(""))}function AA(AK){if(AK.lines.show){a(AK)}if(AK.bars.show){n(AK)}if(AK.points.show){o(AK)}}function a(AN){function AM(AY,AZ,AR,Ad,Ac){var Ae=AY.points,AS=AY.pointsize,AW=null,AV=null;Y.beginPath();for(var AX=AS;AX<Ae.length;AX+=AS){var AU=Ae[AX-AS],Ab=Ae[AX-AS+1],AT=Ae[AX],Aa=Ae[AX+1];if(AU==null||AT==null){continue}if(Ab<=Aa&&Ab<Ac.min){if(Aa<Ac.min){continue}AU=(Ac.min-Ab)/(Aa-Ab)*(AT-AU)+AU;Ab=Ac.min}else{if(Aa<=Ab&&Aa<Ac.min){if(Ab<Ac.min){continue}AT=(Ac.min-Ab)/(Aa-Ab)*(AT-AU)+AU;Aa=Ac.min}}if(Ab>=Aa&&Ab>Ac.max){if(Aa>Ac.max){continue}AU=(Ac.max-Ab)/(Aa-Ab)*(AT-AU)+AU;Ab=Ac.max}else{if(Aa>=Ab&&Aa>Ac.max){if(Ab>Ac.max){continue}AT=(Ac.max-Ab)/(Aa-Ab)*(AT-AU)+AU;Aa=Ac.max}}if(AU<=AT&&AU<Ad.min){if(AT<Ad.min){continue}Ab=(Ad.min-AU)/(AT-AU)*(Aa-Ab)+Ab;AU=Ad.min}else{if(AT<=AU&&AT<Ad.min){if(AU<Ad.min){continue}Aa=(Ad.min-AU)/(AT-AU)*(Aa-Ab)+Ab;AT=Ad.min}}if(AU>=AT&&AU>Ad.max){if(AT>Ad.max){continue}Ab=(Ad.max-AU)/(AT-AU)*(Aa-Ab)+Ab;AU=Ad.max}else{if(AT>=AU&&AT>Ad.max){if(AU>Ad.max){continue}Aa=(Ad.max-AU)/(AT-AU)*(Aa-Ab)+Ab;AT=Ad.max}}if(AU!=AW||Ab!=AV){Y.moveTo(Ad.p2c(AU)+AZ,Ac.p2c(Ab)+AR)}AW=AT;AV=Aa;Y.lineTo(Ad.p2c(AT)+AZ,Ac.p2c(Aa)+AR)}Y.stroke()}function AO(AX,Ae,Ac){var Af=AX.points,AR=AX.pointsize,AS=Math.min(Math.max(0,Ac.min),Ac.max),Aa,AV=0,Ad=false;for(var AW=AR;AW<Af.length;AW+=AR){var AU=Af[AW-AR],Ab=Af[AW-AR+1],AT=Af[AW],AZ=Af[AW+1];if(Ad&&AU!=null&&AT==null){Y.lineTo(Ae.p2c(AV),Ac.p2c(AS));Y.fill();Ad=false;continue}if(AU==null||AT==null){continue}if(AU<=AT&&AU<Ae.min){if(AT<Ae.min){continue}Ab=(Ae.min-AU)/(AT-AU)*(AZ-Ab)+Ab;AU=Ae.min}else{if(AT<=AU&&AT<Ae.min){if(AU<Ae.min){continue}AZ=(Ae.min-AU)/(AT-AU)*(AZ-Ab)+Ab;AT=Ae.min}}if(AU>=AT&&AU>Ae.max){if(AT>Ae.max){continue}Ab=(Ae.max-AU)/(AT-AU)*(AZ-Ab)+Ab;AU=Ae.max}else{if(AT>=AU&&AT>Ae.max){if(AU>Ae.max){continue}AZ=(Ae.max-AU)/(AT-AU)*(AZ-Ab)+Ab;AT=Ae.max}}if(!Ad){Y.beginPath();Y.moveTo(Ae.p2c(AU),Ac.p2c(AS));Ad=true}if(Ab>=Ac.max&&AZ>=Ac.max){Y.lineTo(Ae.p2c(AU),Ac.p2c(Ac.max));Y.lineTo(Ae.p2c(AT),Ac.p2c(Ac.max));AV=AT;continue}else{if(Ab<=Ac.min&&AZ<=Ac.min){Y.lineTo(Ae.p2c(AU),Ac.p2c(Ac.min));Y.lineTo(Ae.p2c(AT),Ac.p2c(Ac.min));AV=AT;continue}}var Ag=AU,AY=AT;if(Ab<=AZ&&Ab<Ac.min&&AZ>=Ac.min){AU=(Ac.min-Ab)/(AZ-Ab)*(AT-AU)+AU;Ab=Ac.min}else{if(AZ<=Ab&&AZ<Ac.min&&Ab>=Ac.min){AT=(Ac.min-Ab)/(AZ-Ab)*(AT-AU)+AU;AZ=Ac.min}}if(Ab>=AZ&&Ab>Ac.max&&AZ<=Ac.max){AU=(Ac.max-Ab)/(AZ-Ab)*(AT-AU)+AU;Ab=Ac.max}else{if(AZ>=Ab&&AZ>Ac.max&&Ab<=Ac.max){AT=(Ac.max-Ab)/(AZ-Ab)*(AT-AU)+AU;AZ=Ac.max}}if(AU!=Ag){if(Ab<=Ac.min){Aa=Ac.min}else{Aa=Ac.max}Y.lineTo(Ae.p2c(Ag),Ac.p2c(Aa));Y.lineTo(Ae.p2c(AU),Ac.p2c(Aa))}Y.lineTo(Ae.p2c(AU),Ac.p2c(Ab));Y.lineTo(Ae.p2c(AT),Ac.p2c(AZ));if(AT!=AY){if(AZ<=Ac.min){Aa=Ac.min}else{Aa=Ac.max}Y.lineTo(Ae.p2c(AT),Ac.p2c(Aa));Y.lineTo(Ae.p2c(AY),Ac.p2c(Aa))}AV=Math.max(AT,AY)}if(Ad){Y.lineTo(Ae.p2c(AV),Ac.p2c(AS));Y.fill()}}Y.save();Y.translate(e.left,e.top);Y.lineJoin="round";var AP=AN.lines.lineWidth,AK=AN.shadowSize;if(AP>0&&AK>0){Y.lineWidth=AK;Y.strokeStyle="rgba(0,0,0,0.1)";var AQ=Math.PI/18;AM(AN.datapoints,Math.sin(AQ)*(AP/2+AK/2),Math.cos(AQ)*(AP/2+AK/2),AN.xaxis,AN.yaxis);Y.lineWidth=AK/2;AM(AN.datapoints,Math.sin(AQ)*(AP/2+AK/4),Math.cos(AQ)*(AP/2+AK/4),AN.xaxis,AN.yaxis)}Y.lineWidth=AP;Y.strokeStyle=AN.color;var AL=V(AN.lines,AN.color,0,t);if(AL){Y.fillStyle=AL;AO(AN.datapoints,AN.xaxis,AN.yaxis)}if(AP>0){AM(AN.datapoints,0,0,AN.xaxis,AN.yaxis)}Y.restore()}function o(AN){function AP(AU,AT,Ab,AR,AV,AZ,AY){var Aa=AU.points,AQ=AU.pointsize;for(var AS=0;AS<Aa.length;AS+=AQ){var AX=Aa[AS],AW=Aa[AS+1];if(AX==null||AX<AZ.min||AX>AZ.max||AW<AY.min||AW>AY.max){continue}Y.beginPath();Y.arc(AZ.p2c(AX),AY.p2c(AW)+AR,AT,0,AV,false);if(Ab){Y.fillStyle=Ab;Y.fill()}Y.stroke()}}Y.save();Y.translate(e.left,e.top);var AO=AN.lines.lineWidth,AL=AN.shadowSize,AK=AN.points.radius;if(AO>0&&AL>0){var AM=AL/2;Y.lineWidth=AM;Y.strokeStyle="rgba(0,0,0,0.1)";AP(AN.datapoints,AK,null,AM+AM/2,Math.PI,AN.xaxis,AN.yaxis);Y.strokeStyle="rgba(0,0,0,0.2)";AP(AN.datapoints,AK,null,AM/2,Math.PI,AN.xaxis,AN.yaxis)}Y.lineWidth=AO;Y.strokeStyle=AN.color;AP(AN.datapoints,AK,V(AN.points,AN.color),0,2*Math.PI,AN.xaxis,AN.yaxis);Y.restore()}function AB(AV,AU,Ad,AQ,AY,AN,AL,AT,AS,Ac,AZ){var AM,Ab,AR,AX,AO,AK,AW,AP,Aa;if(AZ){AP=AK=AW=true;AO=false;AM=Ad;Ab=AV;AX=AU+AQ;AR=AU+AY;if(Ab<AM){Aa=Ab;Ab=AM;AM=Aa;AO=true;AK=false}}else{AO=AK=AW=true;AP=false;AM=AV+AQ;Ab=AV+AY;AR=Ad;AX=AU;if(AX<AR){Aa=AX;AX=AR;AR=Aa;AP=true;AW=false}}if(Ab<AT.min||AM>AT.max||AX<AS.min||AR>AS.max){return }if(AM<AT.min){AM=AT.min;AO=false}if(Ab>AT.max){Ab=AT.max;AK=false}if(AR<AS.min){AR=AS.min;AP=false}if(AX>AS.max){AX=AS.max;AW=false}AM=AT.p2c(AM);AR=AS.p2c(AR);Ab=AT.p2c(Ab);AX=AS.p2c(AX);if(AL){Ac.beginPath();Ac.moveTo(AM,AR);Ac.lineTo(AM,AX);Ac.lineTo(Ab,AX);Ac.lineTo(Ab,AR);Ac.fillStyle=AL(AR,AX);Ac.fill()}if(AO||AK||AW||AP){Ac.beginPath();Ac.moveTo(AM,AR+AN);if(AO){Ac.lineTo(AM,AX+AN)}else{Ac.moveTo(AM,AX+AN)}if(AW){Ac.lineTo(Ab,AX+AN)}else{Ac.moveTo(Ab,AX+AN)}if(AK){Ac.lineTo(Ab,AR+AN)}else{Ac.moveTo(Ab,AR+AN)}if(AP){Ac.lineTo(AM,AR+AN)}else{Ac.moveTo(AM,AR+AN)}Ac.stroke()}}function n(AM){function AL(AS,AR,AU,AP,AT,AW,AV){var AX=AS.points,AO=AS.pointsize;for(var AQ=0;AQ<AX.length;AQ+=AO){if(AX[AQ]==null){continue}AB(AX[AQ],AX[AQ+1],AX[AQ+2],AR,AU,AP,AT,AW,AV,Y,AM.bars.horizontal)}}Y.save();Y.translate(e.left,e.top);Y.lineWidth=AM.bars.lineWidth;Y.strokeStyle=AM.color;var AK=AM.bars.align=="left"?0:-AM.bars.barWidth/2;var AN=AM.bars.fill?function(AO,AP){return V(AM.bars,AM.color,AO,AP)}:null;AL(AM.datapoints,AK,AK+AM.bars.barWidth,0,AN,AM.xaxis,AM.yaxis);Y.restore()}function V(AM,AK,AL,AO){var AN=AM.fill;if(!AN){return null}if(AM.fillColor){return R(AM.fillColor,AL,AO,AK)}var AP=C.color.parse(AK);AP.a=typeof AN=="number"?AN:0.4;AP.normalize();return AP.toString()}function AI(){l.find(".legend").remove();if(!g.legend.show){return }var AP=[],AN=false,AV=g.legend.labelFormatter,AU,AR;for(i=0;i<O.length;++i){AU=O[i];AR=AU.label;if(!AR){continue}if(i%g.legend.noColumns==0){if(AN){AP.push("</tr>")}AP.push("<tr>");AN=true}if(AV){AR=AV(AR,AU)}AP.push('<td class="legendColorBox"><div style="border:1px solid '+g.legend.labelBoxBorderColor+';padding:1px"><div style="width:4px;height:0;border:5px solid '+AU.color+';overflow:hidden"></div></div></td><td class="legendLabel">'+AR+"</td>")}if(AN){AP.push("</tr>")}if(AP.length==0){return }var AT='<table style="font-size:smaller;color:'+g.grid.color+'">'+AP.join("")+"</table>";if(g.legend.container!=null){C(g.legend.container).html(AT)}else{var AQ="",AL=g.legend.position,AM=g.legend.margin;if(AM[0]==null){AM=[AM,AM]}if(AL.charAt(0)=="n"){AQ+="top:"+(AM[1]+e.top)+"px;"}else{if(AL.charAt(0)=="s"){AQ+="bottom:"+(AM[1]+e.bottom)+"px;"}}if(AL.charAt(1)=="e"){AQ+="right:"+(AM[0]+e.right)+"px;"}else{if(AL.charAt(1)=="w"){AQ+="left:"+(AM[0]+e.left)+"px;"}}var AS=C('<div class="legend">'+AT.replace('style="','style="position:absolute;'+AQ+";")+"</div>").appendTo(l);if(g.legend.backgroundOpacity!=0){var AO=g.legend.backgroundColor;if(AO==null){AO=g.grid.backgroundColor;if(AO&&typeof AO=="string"){AO=C.color.parse(AO)}else{AO=C.color.extract(AS,"background-color")}AO.a=1;AO=AO.toString()}var AK=AS.children();C('<div style="position:absolute;width:'+AK.width()+"px;height:"+AK.height()+"px;"+AQ+"background-color:"+AO+';"> </div>').prependTo(AS).css("opacity",g.legend.backgroundOpacity)}}}var w=[],J=null;function AF(AR,AP,AM){var AX=g.grid.mouseActiveRadius,Aj=AX*AX+1,Ah=null,Aa=false,Af,Ad;for(Af=0;Af<O.length;++Af){if(!AM(O[Af])){continue}var AY=O[Af],AQ=AY.xaxis,AO=AY.yaxis,Ae=AY.datapoints.points,Ac=AY.datapoints.pointsize,AZ=AQ.c2p(AR),AW=AO.c2p(AP),AL=AX/AQ.scale,AK=AX/AO.scale;if(AY.lines.show||AY.points.show){for(Ad=0;Ad<Ae.length;Ad+=Ac){var AT=Ae[Ad],AS=Ae[Ad+1];if(AT==null){continue}if(AT-AZ>AL||AT-AZ<-AL||AS-AW>AK||AS-AW<-AK){continue}var AV=Math.abs(AQ.p2c(AT)-AR),AU=Math.abs(AO.p2c(AS)-AP),Ab=AV*AV+AU*AU;if(Ab<=Aj){Aj=Ab;Ah=[Af,Ad/Ac]}}}if(AY.bars.show&&!Ah){var AN=AY.bars.align=="left"?0:-AY.bars.barWidth/2,Ag=AN+AY.bars.barWidth;for(Ad=0;Ad<Ae.length;Ad+=Ac){var AT=Ae[Ad],AS=Ae[Ad+1],Ai=Ae[Ad+2];if(AT==null){continue}if(O[Af].bars.horizontal?(AZ<=Math.max(Ai,AT)&&AZ>=Math.min(Ai,AT)&&AW>=AS+AN&&AW<=AS+Ag):(AZ>=AT+AN&&AZ<=AT+Ag&&AW>=Math.min(Ai,AS)&&AW<=Math.max(Ai,AS))){Ah=[Af,Ad/Ac]}}}}if(Ah){Af=Ah[0];Ad=Ah[1];Ac=O[Af].datapoints.pointsize;return{datapoint:O[Af].datapoints.points.slice(Ad*Ac,(Ad+1)*Ac),dataIndex:Ad,series:O[Af],seriesIndex:Af}}return null}function D(AK){if(g.grid.hoverable){H("plothover",AK,function(AL){return AL.hoverable!=false})}}function d(AK){H("plotclick",AK,function(AL){return AL.clickable!=false})}function H(AL,AK,AM){var AN=AD.offset(),AS={pageX:AK.pageX,pageY:AK.pageY},AQ=AK.pageX-AN.left-e.left,AO=AK.pageY-AN.top-e.top;if(s.xaxis.used){AS.x=s.xaxis.c2p(AQ)}if(s.yaxis.used){AS.y=s.yaxis.c2p(AO)}if(s.x2axis.used){AS.x2=s.x2axis.c2p(AQ)}if(s.y2axis.used){AS.y2=s.y2axis.c2p(AO)}var AT=AF(AQ,AO,AM);if(AT){AT.pageX=parseInt(AT.series.xaxis.p2c(AT.datapoint[0])+AN.left+e.left);AT.pageY=parseInt(AT.series.yaxis.p2c(AT.datapoint[1])+AN.top+e.top)}if(g.grid.autoHighlight){for(var AP=0;AP<w.length;++AP){var AR=w[AP];if(AR.auto==AL&&!(AT&&AR.series==AT.series&&AR.point==AT.datapoint)){x(AR.series,AR.point)}}if(AT){AE(AT.series,AT.datapoint,AL)}}l.trigger(AL,[AS,AT])}function q(){if(!J){J=setTimeout(v,30)}}function v(){J=null;AJ.save();AJ.clearRect(0,0,y,Q);AJ.translate(e.left,e.top);var AL,AK;for(AL=0;AL<w.length;++AL){AK=w[AL];if(AK.series.bars.show){z(AK.series,AK.point)}else{u(AK.series,AK.point)}}AJ.restore();Z(L.drawOverlay,[AJ])}function AE(AM,AK,AN){if(typeof AM=="number"){AM=O[AM]}if(typeof AK=="number"){AK=AM.data[AK]}var AL=j(AM,AK);if(AL==-1){w.push({series:AM,point:AK,auto:AN});q()}else{if(!AN){w[AL].auto=false}}}function x(AM,AK){if(AM==null&&AK==null){w=[];q()}if(typeof AM=="number"){AM=O[AM]}if(typeof AK=="number"){AK=AM.data[AK]}var AL=j(AM,AK);if(AL!=-1){w.splice(AL,1);q()}}function j(AM,AN){for(var AK=0;AK<w.length;++AK){var AL=w[AK];if(AL.series==AM&&AL.point[0]==AN[0]&&AL.point[1]==AN[1]){return AK}}return -1}function u(AN,AM){var AL=AM[0],AR=AM[1],AQ=AN.xaxis,AP=AN.yaxis;if(AL<AQ.min||AL>AQ.max||AR<AP.min||AR>AP.max){return }var AO=AN.points.radius+AN.points.lineWidth/2;AJ.lineWidth=AO;AJ.strokeStyle=C.color.parse(AN.color).scale("a",0.5).toString();var AK=1.5*AO;AJ.beginPath();AJ.arc(AQ.p2c(AL),AP.p2c(AR),AK,0,2*Math.PI,false);AJ.stroke()}function z(AN,AK){AJ.lineWidth=AN.bars.lineWidth;AJ.strokeStyle=C.color.parse(AN.color).scale("a",0.5).toString();var AM=C.color.parse(AN.color).scale("a",0.5).toString();var AL=AN.bars.align=="left"?0:-AN.bars.barWidth/2;AB(AK[0],AK[1],AK[2]||0,AL,AL+AN.bars.barWidth,0,function(){return AM},AN.xaxis,AN.yaxis,AJ,AN.bars.horizontal)}function R(AM,AL,AQ,AO){if(typeof AM=="string"){return AM}else{var AP=Y.createLinearGradient(0,AQ,0,AL);for(var AN=0,AK=AM.colors.length;AN<AK;++AN){var AR=AM.colors[AN];if(typeof AR!="string"){AR=C.color.parse(AO).scale("rgb",AR.brightness);AR.a*=AR.opacity;AR=AR.toString()}AP.addColorStop(AN/(AK-1),AR)}return AP}}}C.plot=function(G,E,D){var F=new B(C(G),E,D,C.plot.plugins);return F};C.plot.plugins=[];C.plot.formatDate=function(H,E,G){var L=function(N){N=""+N;return N.length==1?"0"+N:N};var D=[];var M=false;var K=H.getUTCHours();var I=K<12;if(G==null){G=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]}if(E.search(/%p|%P/)!=-1){if(K>12){K=K-12}else{if(K==0){K=12}}}for(var F=0;F<E.length;++F){var J=E.charAt(F);if(M){switch(J){case"h":J=""+K;break;case"H":J=L(K);break;case"M":J=L(H.getUTCMinutes());break;case"S":J=L(H.getUTCSeconds());break;case"d":J=""+H.getUTCDate();break;case"m":J=""+(H.getUTCMonth()+1);break;case"y":J=""+H.getUTCFullYear();break;case"b":J=""+G[H.getUTCMonth()];break;case"p":J=(I)?("am"):("pm");break;case"P":J=(I)?("AM"):("PM");break}D.push(J);M=false}else{if(J=="%"){M=true}else{D.push(J)}}}return D.join("")};function A(E,D){return D*Math.floor(E/D)}})(jQuery);
@@ -0,0 +1,19 @@
1
+ /*
2
+ * jQuery JavaScript Library v1.3.2
3
+ * http://jquery.com/
4
+ *
5
+ * Copyright (c) 2009 John Resig
6
+ * Dual licensed under the MIT and GPL licenses.
7
+ * http://docs.jquery.com/License
8
+ *
9
+ * Date: 2009-02-19 17:34:21 -0500 (Thu, 19 Feb 2009)
10
+ * Revision: 6246
11
+ */
12
+ (function(){var window=this,undefined,_jQuery=window.jQuery,_$=window.$,jQuery=window.jQuery=window.$=function(selector,context){return new jQuery.fn.init(selector,context)},quickExpr=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,isSimple=/^.[^:#\[\.,]*$/;jQuery.fn=jQuery.prototype={init:function(selector,context){selector=selector||document;if(selector.nodeType){this[0]=selector;this.length=1;this.context=selector;return this}if(typeof selector==="string"){var match=quickExpr.exec(selector);if(match&&(match[1]||!context)){if(match[1]){selector=jQuery.clean([match[1]],context)}else{var elem=document.getElementById(match[3]);if(elem&&elem.id!=match[3]){return jQuery().find(selector)}var ret=jQuery(elem||[]);ret.context=document;ret.selector=selector;return ret}}else{return jQuery(context).find(selector)}}else{if(jQuery.isFunction(selector)){return jQuery(document).ready(selector)}}if(selector.selector&&selector.context){this.selector=selector.selector;this.context=selector.context}return this.setArray(jQuery.isArray(selector)?selector:jQuery.makeArray(selector))},selector:"",jquery:"1.3.2",size:function(){return this.length},get:function(num){return num===undefined?Array.prototype.slice.call(this):this[num]},pushStack:function(elems,name,selector){var ret=jQuery(elems);ret.prevObject=this;ret.context=this.context;if(name==="find"){ret.selector=this.selector+(this.selector?" ":"")+selector}else{if(name){ret.selector=this.selector+"."+name+"("+selector+")"}}return ret},setArray:function(elems){this.length=0;Array.prototype.push.apply(this,elems);return this},each:function(callback,args){return jQuery.each(this,callback,args)},index:function(elem){return jQuery.inArray(elem&&elem.jquery?elem[0]:elem,this)},attr:function(name,value,type){var options=name;if(typeof name==="string"){if(value===undefined){return this[0]&&jQuery[type||"attr"](this[0],name)}else{options={};options[name]=value}}return this.each(function(i){for(name in options){jQuery.attr(type?this.style:this,name,jQuery.prop(this,options[name],type,i,name))}})},css:function(key,value){if((key=="width"||key=="height")&&parseFloat(value)<0){value=undefined}return this.attr(key,value,"curCSS")},text:function(text){if(typeof text!=="object"&&text!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(text))}var ret="";jQuery.each(text||this,function(){jQuery.each(this.childNodes,function(){if(this.nodeType!=8){ret+=this.nodeType!=1?this.nodeValue:jQuery.fn.text([this])}})});return ret},wrapAll:function(html){if(this[0]){var wrap=jQuery(html,this[0].ownerDocument).clone();if(this[0].parentNode){wrap.insertBefore(this[0])}wrap.map(function(){var elem=this;while(elem.firstChild){elem=elem.firstChild}return elem}).append(this)}return this},wrapInner:function(html){return this.each(function(){jQuery(this).contents().wrapAll(html)})},wrap:function(html){return this.each(function(){jQuery(this).wrapAll(html)})},append:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType==1){this.appendChild(elem)}})},prepend:function(){return this.domManip(arguments,true,function(elem){if(this.nodeType==1){this.insertBefore(elem,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this)})},after:function(){return this.domManip(arguments,false,function(elem){this.parentNode.insertBefore(elem,this.nextSibling)})},end:function(){return this.prevObject||jQuery([])},push:[].push,sort:[].sort,splice:[].splice,find:function(selector){if(this.length===1){var ret=this.pushStack([],"find",selector);ret.length=0;jQuery.find(selector,this[0],ret);return ret}else{return this.pushStack(jQuery.unique(jQuery.map(this,function(elem){return jQuery.find(selector,elem)})),"find",selector)}},clone:function(events){var ret=this.map(function(){if(!jQuery.support.noCloneEvent&&!jQuery.isXMLDoc(this)){var html=this.outerHTML;if(!html){var div=this.ownerDocument.createElement("div");div.appendChild(this.cloneNode(true));html=div.innerHTML}return jQuery.clean([html.replace(/ jQuery\d+="(?:\d+|null)"/g,"").replace(/^\s*/,"")])[0]}else{return this.cloneNode(true)}});if(events===true){var orig=this.find("*").andSelf(),i=0;ret.find("*").andSelf().each(function(){if(this.nodeName!==orig[i].nodeName){return }var events=jQuery.data(orig[i],"events");for(var type in events){for(var handler in events[type]){jQuery.event.add(this,type,events[type][handler],events[type][handler].data)}}i++})}return ret},filter:function(selector){return this.pushStack(jQuery.isFunction(selector)&&jQuery.grep(this,function(elem,i){return selector.call(elem,i)})||jQuery.multiFilter(selector,jQuery.grep(this,function(elem){return elem.nodeType===1})),"filter",selector)},closest:function(selector){var pos=jQuery.expr.match.POS.test(selector)?jQuery(selector):null,closer=0;return this.map(function(){var cur=this;while(cur&&cur.ownerDocument){if(pos?pos.index(cur)>-1:jQuery(cur).is(selector)){jQuery.data(cur,"closest",closer);return cur}cur=cur.parentNode;closer++}})},not:function(selector){if(typeof selector==="string"){if(isSimple.test(selector)){return this.pushStack(jQuery.multiFilter(selector,this,true),"not",selector)}else{selector=jQuery.multiFilter(selector,this)}}var isArrayLike=selector.length&&selector[selector.length-1]!==undefined&&!selector.nodeType;return this.filter(function(){return isArrayLike?jQuery.inArray(this,selector)<0:this!=selector})},add:function(selector){return this.pushStack(jQuery.unique(jQuery.merge(this.get(),typeof selector==="string"?jQuery(selector):jQuery.makeArray(selector))))},is:function(selector){return !!selector&&jQuery.multiFilter(selector,this).length>0},hasClass:function(selector){return !!selector&&this.is("."+selector)},val:function(value){if(value===undefined){var elem=this[0];if(elem){if(jQuery.nodeName(elem,"option")){return(elem.attributes.value||{}).specified?elem.value:elem.text}if(jQuery.nodeName(elem,"select")){var index=elem.selectedIndex,values=[],options=elem.options,one=elem.type=="select-one";if(index<0){return null}for(var i=one?index:0,max=one?index+1:options.length;i<max;i++){var option=options[i];if(option.selected){value=jQuery(option).val();if(one){return value}values.push(value)}}return values}return(elem.value||"").replace(/\r/g,"")}return undefined}if(typeof value==="number"){value+=""}return this.each(function(){if(this.nodeType!=1){return }if(jQuery.isArray(value)&&/radio|checkbox/.test(this.type)){this.checked=(jQuery.inArray(this.value,value)>=0||jQuery.inArray(this.name,value)>=0)}else{if(jQuery.nodeName(this,"select")){var values=jQuery.makeArray(value);jQuery("option",this).each(function(){this.selected=(jQuery.inArray(this.value,values)>=0||jQuery.inArray(this.text,values)>=0)});if(!values.length){this.selectedIndex=-1}}else{this.value=value}}})},html:function(value){return value===undefined?(this[0]?this[0].innerHTML.replace(/ jQuery\d+="(?:\d+|null)"/g,""):null):this.empty().append(value)},replaceWith:function(value){return this.after(value).remove()},eq:function(i){return this.slice(i,+i+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(callback){return this.pushStack(jQuery.map(this,function(elem,i){return callback.call(elem,i,elem)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(args,table,callback){if(this[0]){var fragment=(this[0].ownerDocument||this[0]).createDocumentFragment(),scripts=jQuery.clean(args,(this[0].ownerDocument||this[0]),fragment),first=fragment.firstChild;if(first){for(var i=0,l=this.length;i<l;i++){callback.call(root(this[i],first),this.length>1||i>0?fragment.cloneNode(true):fragment)}}if(scripts){jQuery.each(scripts,evalScript)}}return this;function root(elem,cur){return table&&jQuery.nodeName(elem,"table")&&jQuery.nodeName(cur,"tr")?(elem.getElementsByTagName("tbody")[0]||elem.appendChild(elem.ownerDocument.createElement("tbody"))):elem}}};jQuery.fn.init.prototype=jQuery.fn;function evalScript(i,elem){if(elem.src){jQuery.ajax({url:elem.src,async:false,dataType:"script"})}else{jQuery.globalEval(elem.text||elem.textContent||elem.innerHTML||"")}if(elem.parentNode){elem.parentNode.removeChild(elem)}}function now(){return +new Date}jQuery.extend=jQuery.fn.extend=function(){var target=arguments[0]||{},i=1,length=arguments.length,deep=false,options;if(typeof target==="boolean"){deep=target;target=arguments[1]||{};i=2}if(typeof target!=="object"&&!jQuery.isFunction(target)){target={}}if(length==i){target=this;--i}for(;i<length;i++){if((options=arguments[i])!=null){for(var name in options){var src=target[name],copy=options[name];if(target===copy){continue}if(deep&&copy&&typeof copy==="object"&&!copy.nodeType){target[name]=jQuery.extend(deep,src||(copy.length!=null?[]:{}),copy)}else{if(copy!==undefined){target[name]=copy}}}}}return target};var exclude=/z-?index|font-?weight|opacity|zoom|line-?height/i,defaultView=document.defaultView||{},toString=Object.prototype.toString;jQuery.extend({noConflict:function(deep){window.$=_$;if(deep){window.jQuery=_jQuery}return jQuery},isFunction:function(obj){return toString.call(obj)==="[object Function]"},isArray:function(obj){return toString.call(obj)==="[object Array]"},isXMLDoc:function(elem){return elem.nodeType===9&&elem.documentElement.nodeName!=="HTML"||!!elem.ownerDocument&&jQuery.isXMLDoc(elem.ownerDocument)},globalEval:function(data){if(data&&/\S/.test(data)){var head=document.getElementsByTagName("head")[0]||document.documentElement,script=document.createElement("script");script.type="text/javascript";if(jQuery.support.scriptEval){script.appendChild(document.createTextNode(data))}else{script.text=data}head.insertBefore(script,head.firstChild);head.removeChild(script)}},nodeName:function(elem,name){return elem.nodeName&&elem.nodeName.toUpperCase()==name.toUpperCase()},each:function(object,callback,args){var name,i=0,length=object.length;if(args){if(length===undefined){for(name in object){if(callback.apply(object[name],args)===false){break}}}else{for(;i<length;){if(callback.apply(object[i++],args)===false){break}}}}else{if(length===undefined){for(name in object){if(callback.call(object[name],name,object[name])===false){break}}}else{for(var value=object[0];i<length&&callback.call(value,i,value)!==false;value=object[++i]){}}}return object},prop:function(elem,value,type,i,name){if(jQuery.isFunction(value)){value=value.call(elem,i)}return typeof value==="number"&&type=="curCSS"&&!exclude.test(name)?value+"px":value},className:{add:function(elem,classNames){jQuery.each((classNames||"").split(/\s+/),function(i,className){if(elem.nodeType==1&&!jQuery.className.has(elem.className,className)){elem.className+=(elem.className?" ":"")+className}})},remove:function(elem,classNames){if(elem.nodeType==1){elem.className=classNames!==undefined?jQuery.grep(elem.className.split(/\s+/),function(className){return !jQuery.className.has(classNames,className)}).join(" "):""}},has:function(elem,className){return elem&&jQuery.inArray(className,(elem.className||elem).toString().split(/\s+/))>-1}},swap:function(elem,options,callback){var old={};for(var name in options){old[name]=elem.style[name];elem.style[name]=options[name]}callback.call(elem);for(var name in options){elem.style[name]=old[name]}},css:function(elem,name,force,extra){if(name=="width"||name=="height"){var val,props={position:"absolute",visibility:"hidden",display:"block"},which=name=="width"?["Left","Right"]:["Top","Bottom"];function getWH(){val=name=="width"?elem.offsetWidth:elem.offsetHeight;if(extra==="border"){return }jQuery.each(which,function(){if(!extra){val-=parseFloat(jQuery.curCSS(elem,"padding"+this,true))||0}if(extra==="margin"){val+=parseFloat(jQuery.curCSS(elem,"margin"+this,true))||0}else{val-=parseFloat(jQuery.curCSS(elem,"border"+this+"Width",true))||0}})}if(elem.offsetWidth!==0){getWH()}else{jQuery.swap(elem,props,getWH)}return Math.max(0,Math.round(val))}return jQuery.curCSS(elem,name,force)},curCSS:function(elem,name,force){var ret,style=elem.style;if(name=="opacity"&&!jQuery.support.opacity){ret=jQuery.attr(style,"opacity");return ret==""?"1":ret}if(name.match(/float/i)){name=styleFloat}if(!force&&style&&style[name]){ret=style[name]}else{if(defaultView.getComputedStyle){if(name.match(/float/i)){name="float"}name=name.replace(/([A-Z])/g,"-$1").toLowerCase();var computedStyle=defaultView.getComputedStyle(elem,null);if(computedStyle){ret=computedStyle.getPropertyValue(name)}if(name=="opacity"&&ret==""){ret="1"}}else{if(elem.currentStyle){var camelCase=name.replace(/\-(\w)/g,function(all,letter){return letter.toUpperCase()});ret=elem.currentStyle[name]||elem.currentStyle[camelCase];if(!/^\d+(px)?$/i.test(ret)&&/^\d/.test(ret)){var left=style.left,rsLeft=elem.runtimeStyle.left;elem.runtimeStyle.left=elem.currentStyle.left;style.left=ret||0;ret=style.pixelLeft+"px";style.left=left;elem.runtimeStyle.left=rsLeft}}}}return ret},clean:function(elems,context,fragment){context=context||document;if(typeof context.createElement==="undefined"){context=context.ownerDocument||context[0]&&context[0].ownerDocument||document}if(!fragment&&elems.length===1&&typeof elems[0]==="string"){var match=/^<(\w+)\s*\/?>$/.exec(elems[0]);if(match){return[context.createElement(match[1])]}}var ret=[],scripts=[],div=context.createElement("div");jQuery.each(elems,function(i,elem){if(typeof elem==="number"){elem+=""}if(!elem){return }if(typeof elem==="string"){elem=elem.replace(/(<(\w+)[^>]*?)\/>/g,function(all,front,tag){return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?all:front+"></"+tag+">"});var tags=elem.replace(/^\s+/,"").substring(0,10).toLowerCase();var wrap=!tags.indexOf("<opt")&&[1,"<select multiple='multiple'>","</select>"]||!tags.indexOf("<leg")&&[1,"<fieldset>","</fieldset>"]||tags.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,"<table>","</table>"]||!tags.indexOf("<tr")&&[2,"<table><tbody>","</tbody></table>"]||(!tags.indexOf("<td")||!tags.indexOf("<th"))&&[3,"<table><tbody><tr>","</tr></tbody></table>"]||!tags.indexOf("<col")&&[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"]||!jQuery.support.htmlSerialize&&[1,"div<div>","</div>"]||[0,"",""];div.innerHTML=wrap[1]+elem+wrap[2];while(wrap[0]--){div=div.lastChild}if(!jQuery.support.tbody){var hasBody=/<tbody/i.test(elem),tbody=!tags.indexOf("<table")&&!hasBody?div.firstChild&&div.firstChild.childNodes:wrap[1]=="<table>"&&!hasBody?div.childNodes:[];for(var j=tbody.length-1;j>=0;--j){if(jQuery.nodeName(tbody[j],"tbody")&&!tbody[j].childNodes.length){tbody[j].parentNode.removeChild(tbody[j])}}}if(!jQuery.support.leadingWhitespace&&/^\s/.test(elem)){div.insertBefore(context.createTextNode(elem.match(/^\s*/)[0]),div.firstChild)}elem=jQuery.makeArray(div.childNodes)}if(elem.nodeType){ret.push(elem)}else{ret=jQuery.merge(ret,elem)}});if(fragment){for(var i=0;ret[i];i++){if(jQuery.nodeName(ret[i],"script")&&(!ret[i].type||ret[i].type.toLowerCase()==="text/javascript")){scripts.push(ret[i].parentNode?ret[i].parentNode.removeChild(ret[i]):ret[i])}else{if(ret[i].nodeType===1){ret.splice.apply(ret,[i+1,0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))))}fragment.appendChild(ret[i])}}return scripts}return ret},attr:function(elem,name,value){if(!elem||elem.nodeType==3||elem.nodeType==8){return undefined}var notxml=!jQuery.isXMLDoc(elem),set=value!==undefined;name=notxml&&jQuery.props[name]||name;if(elem.tagName){var special=/href|src|style/.test(name);if(name=="selected"&&elem.parentNode){elem.parentNode.selectedIndex}if(name in elem&&notxml&&!special){if(set){if(name=="type"&&jQuery.nodeName(elem,"input")&&elem.parentNode){throw"type property can't be changed"}elem[name]=value}if(jQuery.nodeName(elem,"form")&&elem.getAttributeNode(name)){return elem.getAttributeNode(name).nodeValue}if(name=="tabIndex"){var attributeNode=elem.getAttributeNode("tabIndex");return attributeNode&&attributeNode.specified?attributeNode.value:elem.nodeName.match(/(button|input|object|select|textarea)/i)?0:elem.nodeName.match(/^(a|area)$/i)&&elem.href?0:undefined}return elem[name]}if(!jQuery.support.style&&notxml&&name=="style"){return jQuery.attr(elem.style,"cssText",value)}if(set){elem.setAttribute(name,""+value)}var attr=!jQuery.support.hrefNormalized&&notxml&&special?elem.getAttribute(name,2):elem.getAttribute(name);return attr===null?undefined:attr}if(!jQuery.support.opacity&&name=="opacity"){if(set){elem.zoom=1;elem.filter=(elem.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(value)+""=="NaN"?"":"alpha(opacity="+value*100+")")}return elem.filter&&elem.filter.indexOf("opacity=")>=0?(parseFloat(elem.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}name=name.replace(/-([a-z])/ig,function(all,letter){return letter.toUpperCase()});if(set){elem[name]=value}return elem[name]},trim:function(text){return(text||"").replace(/^\s+|\s+$/g,"")},makeArray:function(array){var ret=[];if(array!=null){var i=array.length;if(i==null||typeof array==="string"||jQuery.isFunction(array)||array.setInterval){ret[0]=array}else{while(i){ret[--i]=array[i]}}}return ret},inArray:function(elem,array){for(var i=0,length=array.length;i<length;i++){if(array[i]===elem){return i}}return -1},merge:function(first,second){var i=0,elem,pos=first.length;if(!jQuery.support.getAll){while((elem=second[i++])!=null){if(elem.nodeType!=8){first[pos++]=elem}}}else{while((elem=second[i++])!=null){first[pos++]=elem}}return first},unique:function(array){var ret=[],done={};try{for(var i=0,length=array.length;i<length;i++){var id=jQuery.data(array[i]);if(!done[id]){done[id]=true;ret.push(array[i])}}}catch(e){ret=array}return ret},grep:function(elems,callback,inv){var ret=[];for(var i=0,length=elems.length;i<length;i++){if(!inv!=!callback(elems[i],i)){ret.push(elems[i])}}return ret},map:function(elems,callback){var ret=[];for(var i=0,length=elems.length;i<length;i++){var value=callback(elems[i],i);if(value!=null){ret[ret.length]=value}}return ret.concat.apply([],ret)}});var userAgent=navigator.userAgent.toLowerCase();jQuery.browser={version:(userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/)||[0,"0"])[1],safari:/webkit/.test(userAgent),opera:/opera/.test(userAgent),msie:/msie/.test(userAgent)&&!/opera/.test(userAgent),mozilla:/mozilla/.test(userAgent)&&!/(compatible|webkit)/.test(userAgent)};jQuery.each({parent:function(elem){return elem.parentNode},parents:function(elem){return jQuery.dir(elem,"parentNode")},next:function(elem){return jQuery.nth(elem,2,"nextSibling")},prev:function(elem){return jQuery.nth(elem,2,"previousSibling")},nextAll:function(elem){return jQuery.dir(elem,"nextSibling")},prevAll:function(elem){return jQuery.dir(elem,"previousSibling")},siblings:function(elem){return jQuery.sibling(elem.parentNode.firstChild,elem)},children:function(elem){return jQuery.sibling(elem.firstChild)},contents:function(elem){return jQuery.nodeName(elem,"iframe")?elem.contentDocument||elem.contentWindow.document:jQuery.makeArray(elem.childNodes)}},function(name,fn){jQuery.fn[name]=function(selector){var ret=jQuery.map(this,fn);if(selector&&typeof selector=="string"){ret=jQuery.multiFilter(selector,ret)}return this.pushStack(jQuery.unique(ret),name,selector)}});jQuery.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(name,original){jQuery.fn[name]=function(selector){var ret=[],insert=jQuery(selector);for(var i=0,l=insert.length;i<l;i++){var elems=(i>0?this.clone(true):this).get();jQuery.fn[original].apply(jQuery(insert[i]),elems);ret=ret.concat(elems)}return this.pushStack(ret,name,selector)}});jQuery.each({removeAttr:function(name){jQuery.attr(this,name,"");if(this.nodeType==1){this.removeAttribute(name)}},addClass:function(classNames){jQuery.className.add(this,classNames)},removeClass:function(classNames){jQuery.className.remove(this,classNames)},toggleClass:function(classNames,state){if(typeof state!=="boolean"){state=!jQuery.className.has(this,classNames)}jQuery.className[state?"add":"remove"](this,classNames)},remove:function(selector){if(!selector||jQuery.filter(selector,[this]).length){jQuery("*",this).add([this]).each(function(){jQuery.event.remove(this);jQuery.removeData(this)});if(this.parentNode){this.parentNode.removeChild(this)}}},empty:function(){jQuery(this).children().remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(name,fn){jQuery.fn[name]=function(){return this.each(fn,arguments)}});function num(elem,prop){return elem[0]&&parseInt(jQuery.curCSS(elem[0],prop,true),10)||0}var expando="jQuery"+now(),uuid=0,windowData={};jQuery.extend({cache:{},data:function(elem,name,data){elem=elem==window?windowData:elem;var id=elem[expando];if(!id){id=elem[expando]=++uuid}if(name&&!jQuery.cache[id]){jQuery.cache[id]={}}if(data!==undefined){jQuery.cache[id][name]=data}return name?jQuery.cache[id][name]:id},removeData:function(elem,name){elem=elem==window?windowData:elem;var id=elem[expando];if(name){if(jQuery.cache[id]){delete jQuery.cache[id][name];name="";for(name in jQuery.cache[id]){break}if(!name){jQuery.removeData(elem)}}}else{try{delete elem[expando]}catch(e){if(elem.removeAttribute){elem.removeAttribute(expando)}}delete jQuery.cache[id]}},queue:function(elem,type,data){if(elem){type=(type||"fx")+"queue";var q=jQuery.data(elem,type);if(!q||jQuery.isArray(data)){q=jQuery.data(elem,type,jQuery.makeArray(data))}else{if(data){q.push(data)}}}return q},dequeue:function(elem,type){var queue=jQuery.queue(elem,type),fn=queue.shift();if(!type||type==="fx"){fn=queue[0]}if(fn!==undefined){fn.call(elem)}}});jQuery.fn.extend({data:function(key,value){var parts=key.split(".");parts[1]=parts[1]?"."+parts[1]:"";if(value===undefined){var data=this.triggerHandler("getData"+parts[1]+"!",[parts[0]]);if(data===undefined&&this.length){data=jQuery.data(this[0],key)}return data===undefined&&parts[1]?this.data(parts[0]):data}else{return this.trigger("setData"+parts[1]+"!",[parts[0],value]).each(function(){jQuery.data(this,key,value)})}},removeData:function(key){return this.each(function(){jQuery.removeData(this,key)})},queue:function(type,data){if(typeof type!=="string"){data=type;type="fx"}if(data===undefined){return jQuery.queue(this[0],type)}return this.each(function(){var queue=jQuery.queue(this,type,data);if(type=="fx"&&queue.length==1){queue[0].call(this)}})},dequeue:function(type){return this.each(function(){jQuery.dequeue(this,type)})}});
13
+ /*
14
+ * Sizzle CSS Selector Engine - v0.9.3
15
+ * Copyright 2009, The Dojo Foundation
16
+ * Released under the MIT, BSD, and GPL Licenses.
17
+ * More information: http://sizzlejs.com/
18
+ */
19
+ (function(){var chunker=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?/g,done=0,toString=Object.prototype.toString;var Sizzle=function(selector,context,results,seed){results=results||[];context=context||document;if(context.nodeType!==1&&context.nodeType!==9){return[]}if(!selector||typeof selector!=="string"){return results}var parts=[],m,set,checkSet,check,mode,extra,prune=true;chunker.lastIndex=0;while((m=chunker.exec(selector))!==null){parts.push(m[1]);if(m[2]){extra=RegExp.rightContext;break}}if(parts.length>1&&origPOS.exec(selector)){if(parts.length===2&&Expr.relative[parts[0]]){set=posProcess(parts[0]+parts[1],context)}else{set=Expr.relative[parts[0]]?[context]:Sizzle(parts.shift(),context);while(parts.length){selector=parts.shift();if(Expr.relative[selector]){selector+=parts.shift()}set=posProcess(selector,set)}}}else{var ret=seed?{expr:parts.pop(),set:makeArray(seed)}:Sizzle.find(parts.pop(),parts.length===1&&context.parentNode?context.parentNode:context,isXML(context));set=Sizzle.filter(ret.expr,ret.set);if(parts.length>0){checkSet=makeArray(set)}else{prune=false}while(parts.length){var cur=parts.pop(),pop=cur;if(!Expr.relative[cur]){cur=""}else{pop=parts.pop()}if(pop==null){pop=context}Expr.relative[cur](checkSet,pop,isXML(context))}}if(!checkSet){checkSet=set}if(!checkSet){throw"Syntax error, unrecognized expression: "+(cur||selector)}if(toString.call(checkSet)==="[object Array]"){if(!prune){results.push.apply(results,checkSet)}else{if(context.nodeType===1){for(var i=0;checkSet[i]!=null;i++){if(checkSet[i]&&(checkSet[i]===true||checkSet[i].nodeType===1&&contains(context,checkSet[i]))){results.push(set[i])}}}else{for(var i=0;checkSet[i]!=null;i++){if(checkSet[i]&&checkSet[i].nodeType===1){results.push(set[i])}}}}}else{makeArray(checkSet,results)}if(extra){Sizzle(extra,context,results,seed);if(sortOrder){hasDuplicate=false;results.sort(sortOrder);if(hasDuplicate){for(var i=1;i<results.length;i++){if(results[i]===results[i-1]){results.splice(i--,1)}}}}}return results};Sizzle.matches=function(expr,set){return Sizzle(expr,null,null,set)};Sizzle.find=function(expr,context,isXML){var set,match;if(!expr){return[]}for(var i=0,l=Expr.order.length;i<l;i++){var type=Expr.order[i],match;if((match=Expr.match[type].exec(expr))){var left=RegExp.leftContext;if(left.substr(left.length-1)!=="\\"){match[1]=(match[1]||"").replace(/\\/g,"");set=Expr.find[type](match,context,isXML);if(set!=null){expr=expr.replace(Expr.match[type],"");break}}}}if(!set){set=context.getElementsByTagName("*")}return{set:set,expr:expr}};Sizzle.filter=function(expr,set,inplace,not){var old=expr,result=[],curLoop=set,match,anyFound,isXMLFilter=set&&set[0]&&isXML(set[0]);while(expr&&set.length){for(var type in Expr.filter){if((match=Expr.match[type].exec(expr))!=null){var filter=Expr.filter[type],found,item;anyFound=false;if(curLoop==result){result=[]}if(Expr.preFilter[type]){match=Expr.preFilter[type](match,curLoop,inplace,result,not,isXMLFilter);if(!match){anyFound=found=true}else{if(match===true){continue}}}if(match){for(var i=0;(item=curLoop[i])!=null;i++){if(item){found=filter(item,match,i,curLoop);var pass=not^!!found;if(inplace&&found!=null){if(pass){anyFound=true}else{curLoop[i]=false}}else{if(pass){result.push(item);anyFound=true}}}}}if(found!==undefined){if(!inplace){curLoop=result}expr=expr.replace(Expr.match[type],"");if(!anyFound){return[]}break}}}if(expr==old){if(anyFound==null){throw"Syntax error, unrecognized expression: "+expr}else{break}}old=expr}return curLoop};var Expr=Sizzle.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF_-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF_-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF_-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*_-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(elem){return elem.getAttribute("href")}},relative:{"+":function(checkSet,part,isXML){var isPartStr=typeof part==="string",isTag=isPartStr&&!/\W/.test(part),isPartStrNotTag=isPartStr&&!isTag;if(isTag&&!isXML){part=part.toUpperCase()}for(var i=0,l=checkSet.length,elem;i<l;i++){if((elem=checkSet[i])){while((elem=elem.previousSibling)&&elem.nodeType!==1){}checkSet[i]=isPartStrNotTag||elem&&elem.nodeName===part?elem||false:elem===part}}if(isPartStrNotTag){Sizzle.filter(part,checkSet,true)}},">":function(checkSet,part,isXML){var isPartStr=typeof part==="string";if(isPartStr&&!/\W/.test(part)){part=isXML?part:part.toUpperCase();for(var i=0,l=checkSet.length;i<l;i++){var elem=checkSet[i];if(elem){var parent=elem.parentNode;checkSet[i]=parent.nodeName===part?parent:false}}}else{for(var i=0,l=checkSet.length;i<l;i++){var elem=checkSet[i];if(elem){checkSet[i]=isPartStr?elem.parentNode:elem.parentNode===part}}if(isPartStr){Sizzle.filter(part,checkSet,true)}}},"":function(checkSet,part,isXML){var doneName=done++,checkFn=dirCheck;if(!part.match(/\W/)){var nodeCheck=part=isXML?part:part.toUpperCase();checkFn=dirNodeCheck}checkFn("parentNode",part,doneName,checkSet,nodeCheck,isXML)},"~":function(checkSet,part,isXML){var doneName=done++,checkFn=dirCheck;if(typeof part==="string"&&!part.match(/\W/)){var nodeCheck=part=isXML?part:part.toUpperCase();checkFn=dirNodeCheck}checkFn("previousSibling",part,doneName,checkSet,nodeCheck,isXML)}},find:{ID:function(match,context,isXML){if(typeof context.getElementById!=="undefined"&&!isXML){var m=context.getElementById(match[1]);return m?[m]:[]}},NAME:function(match,context,isXML){if(typeof context.getElementsByName!=="undefined"){var ret=[],results=context.getElementsByName(match[1]);for(var i=0,l=results.length;i<l;i++){if(results[i].getAttribute("name")===match[1]){ret.push(results[i])}}return ret.length===0?null:ret}},TAG:function(match,context){return context.getElementsByTagName(match[1])}},preFilter:{CLASS:function(match,curLoop,inplace,result,not,isXML){match=" "+match[1].replace(/\\/g,"")+" ";if(isXML){return match}for(var i=0,elem;(elem=curLoop[i])!=null;i++){if(elem){if(not^(elem.className&&(" "+elem.className+" ").indexOf(match)>=0)){if(!inplace){result.push(elem)}}else{if(inplace){curLoop[i]=false}}}}return false},ID:function(match){return match[1].replace(/\\/g,"")},TAG:function(match,curLoop){for(var i=0;curLoop[i]===false;i++){}return curLoop[i]&&isXML(curLoop[i])?match[1]:match[1].toUpperCase()},CHILD:function(match){if(match[1]=="nth"){var test=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(match[2]=="even"&&"2n"||match[2]=="odd"&&"2n+1"||!/\D/.test(match[2])&&"0n+"+match[2]||match[2]);match[2]=(test[1]+(test[2]||1))-0;match[3]=test[3]-0}match[0]=done++;return match},ATTR:function(match,curLoop,inplace,result,not,isXML){var name=match[1].replace(/\\/g,"");if(!isXML&&Expr.attrMap[name]){match[1]=Expr.attrMap[name]}if(match[2]==="~="){match[4]=" "+match[4]+" "}return match},PSEUDO:function(match,curLoop,inplace,result,not){if(match[1]==="not"){if(match[3].match(chunker).length>1||/^\w/.test(match[3])){match[3]=Sizzle(match[3],null,null,curLoop)}else{var ret=Sizzle.filter(match[3],curLoop,inplace,true^not);if(!inplace){result.push.apply(result,ret)}return false}}else{if(Expr.match.POS.test(match[0])||Expr.match.CHILD.test(match[0])){return true}}return match},POS:function(match){match.unshift(true);return match}},filters:{enabled:function(elem){return elem.disabled===false&&elem.type!=="hidden"},disabled:function(elem){return elem.disabled===true},checked:function(elem){return elem.checked===true},selected:function(elem){elem.parentNode.selectedIndex;return elem.selected===true},parent:function(elem){return !!elem.firstChild},empty:function(elem){return !elem.firstChild},has:function(elem,i,match){return !!Sizzle(match[3],elem).length},header:function(elem){return/h\d/i.test(elem.nodeName)},text:function(elem){return"text"===elem.type},radio:function(elem){return"radio"===elem.type},checkbox:function(elem){return"checkbox"===elem.type},file:function(elem){return"file"===elem.type},password:function(elem){return"password"===elem.type},submit:function(elem){return"submit"===elem.type},image:function(elem){return"image"===elem.type},reset:function(elem){return"reset"===elem.type},button:function(elem){return"button"===elem.type||elem.nodeName.toUpperCase()==="BUTTON"},input:function(elem){return/input|select|textarea|button/i.test(elem.nodeName)}},setFilters:{first:function(elem,i){return i===0},last:function(elem,i,match,array){return i===array.length-1},even:function(elem,i){return i%2===0},odd:function(elem,i){return i%2===1},lt:function(elem,i,match){return i<match[3]-0},gt:function(elem,i,match){return i>match[3]-0},nth:function(elem,i,match){return match[3]-0==i},eq:function(elem,i,match){return match[3]-0==i}},filter:{PSEUDO:function(elem,match,i,array){var name=match[1],filter=Expr.filters[name];if(filter){return filter(elem,i,match,array)}else{if(name==="contains"){return(elem.textContent||elem.innerText||"").indexOf(match[3])>=0}else{if(name==="not"){var not=match[3];for(var i=0,l=not.length;i<l;i++){if(not[i]===elem){return false}}return true}}}},CHILD:function(elem,match){var type=match[1],node=elem;switch(type){case"only":case"first":while(node=node.previousSibling){if(node.nodeType===1){return false}}if(type=="first"){return true}node=elem;case"last":while(node=node.nextSibling){if(node.nodeType===1){return false}}return true;case"nth":var first=match[2],last=match[3];if(first==1&&last==0){return true}var doneName=match[0],parent=elem.parentNode;if(parent&&(parent.sizcache!==doneName||!elem.nodeIndex)){var count=0;for(node=parent.firstChild;node;node=node.nextSibling){if(node.nodeType===1){node.nodeIndex=++count}}parent.sizcache=doneName}var diff=elem.nodeIndex-last;if(first==0){return diff==0}else{return(diff%first==0&&diff/first>=0)}}},ID:function(elem,match){return elem.nodeType===1&&elem.getAttribute("id")===match},TAG:function(elem,match){return(match==="*"&&elem.nodeType===1)||elem.nodeName===match},CLASS:function(elem,match){return(" "+(elem.className||elem.getAttribute("class"))+" ").indexOf(match)>-1},ATTR:function(elem,match){var name=match[1],result=Expr.attrHandle[name]?Expr.attrHandle[name](elem):elem[name]!=null?elem[name]:elem.getAttribute(name),value=result+"",type=match[2],check=match[4];return result==null?type==="!=":type==="="?value===check:type==="*="?value.indexOf(check)>=0:type==="~="?(" "+value+" ").indexOf(check)>=0:!check?value&&result!==false:type==="!="?value!=check:type==="^="?value.indexOf(check)===0:type==="$="?value.substr(value.length-check.length)===check:type==="|="?value===check||value.substr(0,check.length+1)===check+"-":false},POS:function(elem,match,i,array){var name=match[2],filter=Expr.setFilters[name];if(filter){return filter(elem,i,match,array)}}}};var origPOS=Expr.match.POS;for(var type in Expr.match){Expr.match[type]=RegExp(Expr.match[type].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var makeArray=function(array,results){array=Array.prototype.slice.call(array);if(results){results.push.apply(results,array);return results}return array};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(e){makeArray=function(array,results){var ret=results||[];if(toString.call(array)==="[object Array]"){Array.prototype.push.apply(ret,array)}else{if(typeof array.length==="number"){for(var i=0,l=array.length;i<l;i++){ret.push(array[i])}}else{for(var i=0;array[i];i++){ret.push(array[i])}}}return ret}}var sortOrder;if(document.documentElement.compareDocumentPosition){sortOrder=function(a,b){var ret=a.compareDocumentPosition(b)&4?-1:a===b?0:1;if(ret===0){hasDuplicate=true}return ret}}else{if("sourceIndex" in document.documentElement){sortOrder=function(a,b){var ret=a.sourceIndex-b.sourceIndex;if(ret===0){hasDuplicate=true}return ret}}else{if(document.createRange){sortOrder=function(a,b){var aRange=a.ownerDocument.createRange(),bRange=b.ownerDocument.createRange();aRange.selectNode(a);aRange.collapse(true);bRange.selectNode(b);bRange.collapse(true);var ret=aRange.compareBoundaryPoints(Range.START_TO_END,bRange);if(ret===0){hasDuplicate=true}return ret}}}}(function(){var form=document.createElement("form"),id="script"+(new Date).getTime();form.innerHTML="<input name='"+id+"'/>";var root=document.documentElement;root.insertBefore(form,root.firstChild);if(!!document.getElementById(id)){Expr.find.ID=function(match,context,isXML){if(typeof context.getElementById!=="undefined"&&!isXML){var m=context.getElementById(match[1]);return m?m.id===match[1]||typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id").nodeValue===match[1]?[m]:undefined:[]}};Expr.filter.ID=function(elem,match){var node=typeof elem.getAttributeNode!=="undefined"&&elem.getAttributeNode("id");return elem.nodeType===1&&node&&node.nodeValue===match}}root.removeChild(form)})();(function(){var div=document.createElement("div");div.appendChild(document.createComment(""));if(div.getElementsByTagName("*").length>0){Expr.find.TAG=function(match,context){var results=context.getElementsByTagName(match[1]);if(match[1]==="*"){var tmp=[];for(var i=0;results[i];i++){if(results[i].nodeType===1){tmp.push(results[i])}}results=tmp}return results}}div.innerHTML="<a href='#'></a>";if(div.firstChild&&typeof div.firstChild.getAttribute!=="undefined"&&div.firstChild.getAttribute("href")!=="#"){Expr.attrHandle.href=function(elem){return elem.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var oldSizzle=Sizzle,div=document.createElement("div");div.innerHTML="<p class='TEST'></p>";if(div.querySelectorAll&&div.querySelectorAll(".TEST").length===0){return }Sizzle=function(query,context,extra,seed){context=context||document;if(!seed&&context.nodeType===9&&!isXML(context)){try{return makeArray(context.querySelectorAll(query),extra)}catch(e){}}return oldSizzle(query,context,extra,seed)};Sizzle.find=oldSizzle.find;Sizzle.filter=oldSizzle.filter;Sizzle.selectors=oldSizzle.selectors;Sizzle.matches=oldSizzle.matches})()}if(document.getElementsByClassName&&document.documentElement.getElementsByClassName){(function(){var div=document.createElement("div");div.innerHTML="<div class='test e'></div><div class='test'></div>";if(div.getElementsByClassName("e").length===0){return }div.lastChild.className="e";if(div.getElementsByClassName("e").length===1){return }Expr.order.splice(1,0,"CLASS");Expr.find.CLASS=function(match,context,isXML){if(typeof context.getElementsByClassName!=="undefined"&&!isXML){return context.getElementsByClassName(match[1])}}})()}function dirNodeCheck(dir,cur,doneName,checkSet,nodeCheck,isXML){var sibDir=dir=="previousSibling"&&!isXML;for(var i=0,l=checkSet.length;i<l;i++){var elem=checkSet[i];if(elem){if(sibDir&&elem.nodeType===1){elem.sizcache=doneName;elem.sizset=i}elem=elem[dir];var match=false;while(elem){if(elem.sizcache===doneName){match=checkSet[elem.sizset];break}if(elem.nodeType===1&&!isXML){elem.sizcache=doneName;elem.sizset=i}if(elem.nodeName===cur){match=elem;break}elem=elem[dir]}checkSet[i]=match}}}function dirCheck(dir,cur,doneName,checkSet,nodeCheck,isXML){var sibDir=dir=="previousSibling"&&!isXML;for(var i=0,l=checkSet.length;i<l;i++){var elem=checkSet[i];if(elem){if(sibDir&&elem.nodeType===1){elem.sizcache=doneName;elem.sizset=i}elem=elem[dir];var match=false;while(elem){if(elem.sizcache===doneName){match=checkSet[elem.sizset];break}if(elem.nodeType===1){if(!isXML){elem.sizcache=doneName;elem.sizset=i}if(typeof cur!=="string"){if(elem===cur){match=true;break}}else{if(Sizzle.filter(cur,[elem]).length>0){match=elem;break}}}elem=elem[dir]}checkSet[i]=match}}}var contains=document.compareDocumentPosition?function(a,b){return a.compareDocumentPosition(b)&16}:function(a,b){return a!==b&&(a.contains?a.contains(b):true)};var isXML=function(elem){return elem.nodeType===9&&elem.documentElement.nodeName!=="HTML"||!!elem.ownerDocument&&isXML(elem.ownerDocument)};var posProcess=function(selector,context){var tmpSet=[],later="",match,root=context.nodeType?[context]:context;while((match=Expr.match.PSEUDO.exec(selector))){later+=match[0];selector=selector.replace(Expr.match.PSEUDO,"")}selector=Expr.relative[selector]?selector+"*":selector;for(var i=0,l=root.length;i<l;i++){Sizzle(selector,root[i],tmpSet)}return Sizzle.filter(later,tmpSet)};jQuery.find=Sizzle;jQuery.filter=Sizzle.filter;jQuery.expr=Sizzle.selectors;jQuery.expr[":"]=jQuery.expr.filters;Sizzle.selectors.filters.hidden=function(elem){return elem.offsetWidth===0||elem.offsetHeight===0};Sizzle.selectors.filters.visible=function(elem){return elem.offsetWidth>0||elem.offsetHeight>0};Sizzle.selectors.filters.animated=function(elem){return jQuery.grep(jQuery.timers,function(fn){return elem===fn.elem}).length};jQuery.multiFilter=function(expr,elems,not){if(not){expr=":not("+expr+")"}return Sizzle.matches(expr,elems)};jQuery.dir=function(elem,dir){var matched=[],cur=elem[dir];while(cur&&cur!=document){if(cur.nodeType==1){matched.push(cur)}cur=cur[dir]}return matched};jQuery.nth=function(cur,result,dir,elem){result=result||1;var num=0;for(;cur;cur=cur[dir]){if(cur.nodeType==1&&++num==result){break}}return cur};jQuery.sibling=function(n,elem){var r=[];for(;n;n=n.nextSibling){if(n.nodeType==1&&n!=elem){r.push(n)}}return r};return ;window.Sizzle=Sizzle})();jQuery.event={add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8){return }if(elem.setInterval&&elem!=window){elem=window}if(!handler.guid){handler.guid=this.guid++}if(data!==undefined){var fn=handler;handler=this.proxy(fn);handler.data=data}var events=jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),handle=jQuery.data(elem,"handle")||jQuery.data(elem,"handle",function(){return typeof jQuery!=="undefined"&&!jQuery.event.triggered?jQuery.event.handle.apply(arguments.callee.elem,arguments):undefined});handle.elem=elem;jQuery.each(types.split(/\s+/),function(index,type){var namespaces=type.split(".");type=namespaces.shift();handler.type=namespaces.slice().sort().join(".");var handlers=events[type];if(jQuery.event.specialAll[type]){jQuery.event.specialAll[type].setup.call(elem,data,namespaces)}if(!handlers){handlers=events[type]={};if(!jQuery.event.special[type]||jQuery.event.special[type].setup.call(elem,data,namespaces)===false){if(elem.addEventListener){elem.addEventListener(type,handle,false)}else{if(elem.attachEvent){elem.attachEvent("on"+type,handle)}}}}handlers[handler.guid]=handler;jQuery.event.global[type]=true});elem=null},guid:1,global:{},remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8){return }var events=jQuery.data(elem,"events"),ret,index;if(events){if(types===undefined||(typeof types==="string"&&types.charAt(0)==".")){for(var type in events){this.remove(elem,type+(types||""))}}else{if(types.type){handler=types.handler;types=types.type}jQuery.each(types.split(/\s+/),function(index,type){var namespaces=type.split(".");type=namespaces.shift();var namespace=RegExp("(^|\\.)"+namespaces.slice().sort().join(".*\\.")+"(\\.|$)");if(events[type]){if(handler){delete events[type][handler.guid]}else{for(var handle in events[type]){if(namespace.test(events[type][handle].type)){delete events[type][handle]}}}if(jQuery.event.specialAll[type]){jQuery.event.specialAll[type].teardown.call(elem,namespaces)}for(ret in events[type]){break}if(!ret){if(!jQuery.event.special[type]||jQuery.event.special[type].teardown.call(elem,namespaces)===false){if(elem.removeEventListener){elem.removeEventListener(type,jQuery.data(elem,"handle"),false)}else{if(elem.detachEvent){elem.detachEvent("on"+type,jQuery.data(elem,"handle"))}}}ret=null;delete events[type]}}})}for(ret in events){break}if(!ret){var handle=jQuery.data(elem,"handle");if(handle){handle.elem=null}jQuery.removeData(elem,"events");jQuery.removeData(elem,"handle")}}},trigger:function(event,data,elem,bubbling){var type=event.type||event;if(!bubbling){event=typeof event==="object"?event[expando]?event:jQuery.extend(jQuery.Event(type),event):jQuery.Event(type);if(type.indexOf("!")>=0){event.type=type=type.slice(0,-1);event.exclusive=true}if(!elem){event.stopPropagation();if(this.global[type]){jQuery.each(jQuery.cache,function(){if(this.events&&this.events[type]){jQuery.event.trigger(event,data,this.handle.elem)}})}}if(!elem||elem.nodeType==3||elem.nodeType==8){return undefined}event.result=undefined;event.target=elem;data=jQuery.makeArray(data);data.unshift(event)}event.currentTarget=elem;var handle=jQuery.data(elem,"handle");if(handle){handle.apply(elem,data)}if((!elem[type]||(jQuery.nodeName(elem,"a")&&type=="click"))&&elem["on"+type]&&elem["on"+type].apply(elem,data)===false){event.result=false}if(!bubbling&&elem[type]&&!event.isDefaultPrevented()&&!(jQuery.nodeName(elem,"a")&&type=="click")){this.triggered=true;try{elem[type]()}catch(e){}}this.triggered=false;if(!event.isPropagationStopped()){var parent=elem.parentNode||elem.ownerDocument;if(parent){jQuery.event.trigger(event,data,parent,true)}}},handle:function(event){var all,handlers;event=arguments[0]=jQuery.event.fix(event||window.event);event.currentTarget=this;var namespaces=event.type.split(".");event.type=namespaces.shift();all=!namespaces.length&&!event.exclusive;var namespace=RegExp("(^|\\.)"+namespaces.slice().sort().join(".*\\.")+"(\\.|$)");handlers=(jQuery.data(this,"events")||{})[event.type];for(var j in handlers){var handler=handlers[j];if(all||namespace.test(handler.type)){event.handler=handler;event.data=handler.data;var ret=handler.apply(this,arguments);if(ret!==undefined){event.result=ret;if(ret===false){event.preventDefault();event.stopPropagation()}}if(event.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(event){if(event[expando]){return event}var originalEvent=event;event=jQuery.Event(originalEvent);for(var i=this.props.length,prop;i;){prop=this.props[--i];event[prop]=originalEvent[prop]}if(!event.target){event.target=event.srcElement||document}if(event.target.nodeType==3){event.target=event.target.parentNode}if(!event.relatedTarget&&event.fromElement){event.relatedTarget=event.fromElement==event.target?event.toElement:event.fromElement}if(event.pageX==null&&event.clientX!=null){var doc=document.documentElement,body=document.body;event.pageX=event.clientX+(doc&&doc.scrollLeft||body&&body.scrollLeft||0)-(doc.clientLeft||0);event.pageY=event.clientY+(doc&&doc.scrollTop||body&&body.scrollTop||0)-(doc.clientTop||0)}if(!event.which&&((event.charCode||event.charCode===0)?event.charCode:event.keyCode)){event.which=event.charCode||event.keyCode}if(!event.metaKey&&event.ctrlKey){event.metaKey=event.ctrlKey}if(!event.which&&event.button){event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)))}return event},proxy:function(fn,proxy){proxy=proxy||function(){return fn.apply(this,arguments)};proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;return proxy},special:{ready:{setup:bindReady,teardown:function(){}}},specialAll:{live:{setup:function(selector,namespaces){jQuery.event.add(this,namespaces[0],liveHandler)},teardown:function(namespaces){if(namespaces.length){var remove=0,name=RegExp("(^|\\.)"+namespaces[0]+"(\\.|$)");jQuery.each((jQuery.data(this,"events").live||{}),function(){if(name.test(this.type)){remove++}});if(remove<1){jQuery.event.remove(this,namespaces[0],liveHandler)}}}}}};jQuery.Event=function(src){if(!this.preventDefault){return new jQuery.Event(src)}if(src&&src.type){this.originalEvent=src;this.type=src.type}else{this.type=src}this.timeStamp=now();this[expando]=true};function returnFalse(){return false}function returnTrue(){return true}jQuery.Event.prototype={preventDefault:function(){this.isDefaultPrevented=returnTrue;var e=this.originalEvent;if(!e){return }if(e.preventDefault){e.preventDefault()}e.returnValue=false},stopPropagation:function(){this.isPropagationStopped=returnTrue;var e=this.originalEvent;if(!e){return }if(e.stopPropagation){e.stopPropagation()}e.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=returnTrue;this.stopPropagation()},isDefaultPrevented:returnFalse,isPropagationStopped:returnFalse,isImmediatePropagationStopped:returnFalse};var withinElement=function(event){var parent=event.relatedTarget;while(parent&&parent!=this){try{parent=parent.parentNode}catch(e){parent=this}}if(parent!=this){event.type=event.data;jQuery.event.handle.apply(this,arguments)}};jQuery.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(orig,fix){jQuery.event.special[fix]={setup:function(){jQuery.event.add(this,orig,withinElement,fix)},teardown:function(){jQuery.event.remove(this,orig,withinElement)}}});jQuery.fn.extend({bind:function(type,data,fn){return type=="unload"?this.one(type,data,fn):this.each(function(){jQuery.event.add(this,type,fn||data,fn&&data)})},one:function(type,data,fn){var one=jQuery.event.proxy(fn||data,function(event){jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments)});return this.each(function(){jQuery.event.add(this,type,one,fn&&data)})},unbind:function(type,fn){return this.each(function(){jQuery.event.remove(this,type,fn)})},trigger:function(type,data){return this.each(function(){jQuery.event.trigger(type,data,this)})},triggerHandler:function(type,data){if(this[0]){var event=jQuery.Event(type);event.preventDefault();event.stopPropagation();jQuery.event.trigger(event,data,this[0]);return event.result}},toggle:function(fn){var args=arguments,i=1;while(i<args.length){jQuery.event.proxy(fn,args[i++])}return this.click(jQuery.event.proxy(fn,function(event){this.lastToggle=(this.lastToggle||0)%i;event.preventDefault();return args[this.lastToggle++].apply(this,arguments)||false}))},hover:function(fnOver,fnOut){return this.mouseenter(fnOver).mouseleave(fnOut)},ready:function(fn){bindReady();if(jQuery.isReady){fn.call(document,jQuery)}else{jQuery.readyList.push(fn)}return this},live:function(type,fn){var proxy=jQuery.event.proxy(fn);proxy.guid+=this.selector+type;jQuery(document).bind(liveConvert(type,this.selector),this.selector,proxy);return this},die:function(type,fn){jQuery(document).unbind(liveConvert(type,this.selector),fn?{guid:fn.guid+this.selector+type}:null);return this}});function liveHandler(event){var check=RegExp("(^|\\.)"+event.type+"(\\.|$)"),stop=true,elems=[];jQuery.each(jQuery.data(this,"events").live||[],function(i,fn){if(check.test(fn.type)){var elem=jQuery(event.target).closest(fn.data)[0];if(elem){elems.push({elem:elem,fn:fn})}}});elems.sort(function(a,b){return jQuery.data(a.elem,"closest")-jQuery.data(b.elem,"closest")});jQuery.each(elems,function(){if(this.fn.call(this.elem,event,this.fn.data)===false){return(stop=false)}});return stop}function liveConvert(type,selector){return["live",type,selector.replace(/\./g,"`").replace(/ /g,"|")].join(".")}jQuery.extend({isReady:false,readyList:[],ready:function(){if(!jQuery.isReady){jQuery.isReady=true;if(jQuery.readyList){jQuery.each(jQuery.readyList,function(){this.call(document,jQuery)});jQuery.readyList=null}jQuery(document).triggerHandler("ready")}}});var readyBound=false;function bindReady(){if(readyBound){return }readyBound=true;if(document.addEventListener){document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,false);jQuery.ready()},false)}else{if(document.attachEvent){document.attachEvent("onreadystatechange",function(){if(document.readyState==="complete"){document.detachEvent("onreadystatechange",arguments.callee);jQuery.ready()}});if(document.documentElement.doScroll&&window==window.top){(function(){if(jQuery.isReady){return }try{document.documentElement.doScroll("left")}catch(error){setTimeout(arguments.callee,0);return }jQuery.ready()})()}}}jQuery.event.add(window,"load",jQuery.ready)}jQuery.each(("blur,focus,load,resize,scroll,unload,click,dblclick,mousedown,mouseup,mousemove,mouseover,mouseout,mouseenter,mouseleave,change,select,submit,keydown,keypress,keyup,error").split(","),function(i,name){jQuery.fn[name]=function(fn){return fn?this.bind(name,fn):this.trigger(name)}});jQuery(window).bind("unload",function(){for(var id in jQuery.cache){if(id!=1&&jQuery.cache[id].handle){jQuery.event.remove(jQuery.cache[id].handle.elem)}}});(function(){jQuery.support={};var root=document.documentElement,script=document.createElement("script"),div=document.createElement("div"),id="script"+(new Date).getTime();div.style.display="none";div.innerHTML=' <link/><table></table><a href="/a" style="color:red;float:left;opacity:.5;">a</a><select><option>text</option></select><object><param/></object>';var all=div.getElementsByTagName("*"),a=div.getElementsByTagName("a")[0];if(!all||!all.length||!a){return }jQuery.support={leadingWhitespace:div.firstChild.nodeType==3,tbody:!div.getElementsByTagName("tbody").length,objectAll:!!div.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!div.getElementsByTagName("link").length,style:/red/.test(a.getAttribute("style")),hrefNormalized:a.getAttribute("href")==="/a",opacity:a.style.opacity==="0.5",cssFloat:!!a.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};script.type="text/javascript";try{script.appendChild(document.createTextNode("window."+id+"=1;"))}catch(e){}root.insertBefore(script,root.firstChild);if(window[id]){jQuery.support.scriptEval=true;delete window[id]}root.removeChild(script);if(div.attachEvent&&div.fireEvent){div.attachEvent("onclick",function(){jQuery.support.noCloneEvent=false;div.detachEvent("onclick",arguments.callee)});div.cloneNode(true).fireEvent("onclick")}jQuery(function(){var div=document.createElement("div");div.style.width=div.style.paddingLeft="1px";document.body.appendChild(div);jQuery.boxModel=jQuery.support.boxModel=div.offsetWidth===2;document.body.removeChild(div).style.display="none"})})();var styleFloat=jQuery.support.cssFloat?"cssFloat":"styleFloat";jQuery.props={"for":"htmlFor","class":"className","float":styleFloat,cssFloat:styleFloat,styleFloat:styleFloat,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};jQuery.fn.extend({_load:jQuery.fn.load,load:function(url,params,callback){if(typeof url!=="string"){return this._load(url)}var off=url.indexOf(" ");if(off>=0){var selector=url.slice(off,url.length);url=url.slice(0,off)}var type="GET";if(params){if(jQuery.isFunction(params)){callback=params;params=null}else{if(typeof params==="object"){params=jQuery.param(params);type="POST"}}}var self=this;jQuery.ajax({url:url,type:type,dataType:"html",data:params,complete:function(res,status){if(status=="success"||status=="notmodified"){self.html(selector?jQuery("<div/>").append(res.responseText.replace(/<script(.|\s)*?\/script>/g,"")).find(selector):res.responseText)}if(callback){self.each(callback,[res.responseText,status,res])}}});return this},serialize:function(){return jQuery.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?jQuery.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||/select|textarea/i.test(this.nodeName)||/text|hidden|password|search/i.test(this.type))}).map(function(i,elem){var val=jQuery(this).val();return val==null?null:jQuery.isArray(val)?jQuery.map(val,function(val,i){return{name:elem.name,value:val}}):{name:elem.name,value:val}}).get()}});jQuery.each("ajaxStart,ajaxStop,ajaxComplete,ajaxError,ajaxSuccess,ajaxSend".split(","),function(i,o){jQuery.fn[o]=function(f){return this.bind(o,f)}});var jsc=now();jQuery.extend({get:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data=null}return jQuery.ajax({type:"GET",url:url,data:data,success:callback,dataType:type})},getScript:function(url,callback){return jQuery.get(url,null,callback,"script")},getJSON:function(url,data,callback){return jQuery.get(url,data,callback,"json")},post:function(url,data,callback,type){if(jQuery.isFunction(data)){callback=data;data={}}return jQuery.ajax({type:"POST",url:url,data:data,success:callback,dataType:type})},ajaxSetup:function(settings){jQuery.extend(jQuery.ajaxSettings,settings)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return window.ActiveXObject?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest()},accepts:{xml:"application/xml, text/xml",html:"text/html",script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},lastModified:{},ajax:function(s){s=jQuery.extend(true,s,jQuery.extend(true,{},jQuery.ajaxSettings,s));var jsonp,jsre=/=\?(&|$)/g,status,data,type=s.type.toUpperCase();if(s.data&&s.processData&&typeof s.data!=="string"){s.data=jQuery.param(s.data)}if(s.dataType=="jsonp"){if(type=="GET"){if(!s.url.match(jsre)){s.url+=(s.url.match(/\?/)?"&":"?")+(s.jsonp||"callback")+"=?"}}else{if(!s.data||!s.data.match(jsre)){s.data=(s.data?s.data+"&":"")+(s.jsonp||"callback")+"=?"}}s.dataType="json"}if(s.dataType=="json"&&(s.data&&s.data.match(jsre)||s.url.match(jsre))){jsonp="jsonp"+jsc++;if(s.data){s.data=(s.data+"").replace(jsre,"="+jsonp+"$1")}s.url=s.url.replace(jsre,"="+jsonp+"$1");s.dataType="script";window[jsonp]=function(tmp){data=tmp;success();complete();window[jsonp]=undefined;try{delete window[jsonp]}catch(e){}if(head){head.removeChild(script)}}}if(s.dataType=="script"&&s.cache==null){s.cache=false}if(s.cache===false&&type=="GET"){var ts=now();var ret=s.url.replace(/(\?|&)_=.*?(&|$)/,"$1_="+ts+"$2");s.url=ret+((ret==s.url)?(s.url.match(/\?/)?"&":"?")+"_="+ts:"")}if(s.data&&type=="GET"){s.url+=(s.url.match(/\?/)?"&":"?")+s.data;s.data=null}if(s.global&&!jQuery.active++){jQuery.event.trigger("ajaxStart")}var parts=/^(\w+:)?\/\/([^\/?#]+)/.exec(s.url);if(s.dataType=="script"&&type=="GET"&&parts&&(parts[1]&&parts[1]!=location.protocol||parts[2]!=location.host)){var head=document.getElementsByTagName("head")[0];var script=document.createElement("script");script.src=s.url;if(s.scriptCharset){script.charset=s.scriptCharset}if(!jsonp){var done=false;script.onload=script.onreadystatechange=function(){if(!done&&(!this.readyState||this.readyState=="loaded"||this.readyState=="complete")){done=true;success();complete();script.onload=script.onreadystatechange=null;head.removeChild(script)}}}head.appendChild(script);return undefined}var requestDone=false;var xhr=s.xhr();if(s.username){xhr.open(type,s.url,s.async,s.username,s.password)}else{xhr.open(type,s.url,s.async)}try{if(s.data){xhr.setRequestHeader("Content-Type",s.contentType)}if(s.ifModified){xhr.setRequestHeader("If-Modified-Since",jQuery.lastModified[s.url]||"Thu, 01 Jan 1970 00:00:00 GMT")}xhr.setRequestHeader("X-Requested-With","XMLHttpRequest");xhr.setRequestHeader("Accept",s.dataType&&s.accepts[s.dataType]?s.accepts[s.dataType]+", */*":s.accepts._default)}catch(e){}if(s.beforeSend&&s.beforeSend(xhr,s)===false){if(s.global&&!--jQuery.active){jQuery.event.trigger("ajaxStop")}xhr.abort();return false}if(s.global){jQuery.event.trigger("ajaxSend",[xhr,s])}var onreadystatechange=function(isTimeout){if(xhr.readyState==0){if(ival){clearInterval(ival);ival=null;if(s.global&&!--jQuery.active){jQuery.event.trigger("ajaxStop")}}}else{if(!requestDone&&xhr&&(xhr.readyState==4||isTimeout=="timeout")){requestDone=true;if(ival){clearInterval(ival);ival=null}status=isTimeout=="timeout"?"timeout":!jQuery.httpSuccess(xhr)?"error":s.ifModified&&jQuery.httpNotModified(xhr,s.url)?"notmodified":"success";if(status=="success"){try{data=jQuery.httpData(xhr,s.dataType,s)}catch(e){status="parsererror"}}if(status=="success"){var modRes;try{modRes=xhr.getResponseHeader("Last-Modified")}catch(e){}if(s.ifModified&&modRes){jQuery.lastModified[s.url]=modRes}if(!jsonp){success()}}else{jQuery.handleError(s,xhr,status)}complete();if(isTimeout){xhr.abort()}if(s.async){xhr=null}}}};if(s.async){var ival=setInterval(onreadystatechange,13);if(s.timeout>0){setTimeout(function(){if(xhr&&!requestDone){onreadystatechange("timeout")}},s.timeout)}}try{xhr.send(s.data)}catch(e){jQuery.handleError(s,xhr,null,e)}if(!s.async){onreadystatechange()}function success(){if(s.success){s.success(data,status)}if(s.global){jQuery.event.trigger("ajaxSuccess",[xhr,s])}}function complete(){if(s.complete){s.complete(xhr,status)}if(s.global){jQuery.event.trigger("ajaxComplete",[xhr,s])}if(s.global&&!--jQuery.active){jQuery.event.trigger("ajaxStop")}}return xhr},handleError:function(s,xhr,status,e){if(s.error){s.error(xhr,status,e)}if(s.global){jQuery.event.trigger("ajaxError",[xhr,s,e])}},active:0,httpSuccess:function(xhr){try{return !xhr.status&&location.protocol=="file:"||(xhr.status>=200&&xhr.status<300)||xhr.status==304||xhr.status==1223}catch(e){}return false},httpNotModified:function(xhr,url){try{var xhrRes=xhr.getResponseHeader("Last-Modified");return xhr.status==304||xhrRes==jQuery.lastModified[url]}catch(e){}return false},httpData:function(xhr,type,s){var ct=xhr.getResponseHeader("content-type"),xml=type=="xml"||!type&&ct&&ct.indexOf("xml")>=0,data=xml?xhr.responseXML:xhr.responseText;if(xml&&data.documentElement.tagName=="parsererror"){throw"parsererror"}if(s&&s.dataFilter){data=s.dataFilter(data,type)}if(typeof data==="string"){if(type=="script"){jQuery.globalEval(data)}if(type=="json"){data=window["eval"]("("+data+")")}}return data},param:function(a){var s=[];function add(key,value){s[s.length]=encodeURIComponent(key)+"="+encodeURIComponent(value)}if(jQuery.isArray(a)||a.jquery){jQuery.each(a,function(){add(this.name,this.value)})}else{for(var j in a){if(jQuery.isArray(a[j])){jQuery.each(a[j],function(){add(j,this)})}else{add(j,jQuery.isFunction(a[j])?a[j]():a[j])}}}return s.join("&").replace(/%20/g,"+")}});var elemdisplay={},timerId,fxAttrs=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];function genFx(type,num){var obj={};jQuery.each(fxAttrs.concat.apply([],fxAttrs.slice(0,num)),function(){obj[this]=type});return obj}jQuery.fn.extend({show:function(speed,callback){if(speed){return this.animate(genFx("show",3),speed,callback)}else{for(var i=0,l=this.length;i<l;i++){var old=jQuery.data(this[i],"olddisplay");this[i].style.display=old||"";if(jQuery.css(this[i],"display")==="none"){var tagName=this[i].tagName,display;if(elemdisplay[tagName]){display=elemdisplay[tagName]}else{var elem=jQuery("<"+tagName+" />").appendTo("body");display=elem.css("display");if(display==="none"){display="block"}elem.remove();elemdisplay[tagName]=display}jQuery.data(this[i],"olddisplay",display)}}for(var i=0,l=this.length;i<l;i++){this[i].style.display=jQuery.data(this[i],"olddisplay")||""}return this}},hide:function(speed,callback){if(speed){return this.animate(genFx("hide",3),speed,callback)}else{for(var i=0,l=this.length;i<l;i++){var old=jQuery.data(this[i],"olddisplay");if(!old&&old!=="none"){jQuery.data(this[i],"olddisplay",jQuery.css(this[i],"display"))}}for(var i=0,l=this.length;i<l;i++){this[i].style.display="none"}return this}},_toggle:jQuery.fn.toggle,toggle:function(fn,fn2){var bool=typeof fn==="boolean";return jQuery.isFunction(fn)&&jQuery.isFunction(fn2)?this._toggle.apply(this,arguments):fn==null||bool?this.each(function(){var state=bool?fn:jQuery(this).is(":hidden");jQuery(this)[state?"show":"hide"]()}):this.animate(genFx("toggle",3),fn,fn2)},fadeTo:function(speed,to,callback){return this.animate({opacity:to},speed,callback)},animate:function(prop,speed,easing,callback){var optall=jQuery.speed(speed,easing,callback);return this[optall.queue===false?"each":"queue"](function(){var opt=jQuery.extend({},optall),p,hidden=this.nodeType==1&&jQuery(this).is(":hidden"),self=this;for(p in prop){if(prop[p]=="hide"&&hidden||prop[p]=="show"&&!hidden){return opt.complete.call(this)}if((p=="height"||p=="width")&&this.style){opt.display=jQuery.css(this,"display");opt.overflow=this.style.overflow}}if(opt.overflow!=null){this.style.overflow="hidden"}opt.curAnim=jQuery.extend({},prop);jQuery.each(prop,function(name,val){var e=new jQuery.fx(self,opt,name);if(/toggle|show|hide/.test(val)){e[val=="toggle"?hidden?"show":"hide":val](prop)}else{var parts=val.toString().match(/^([+-]=)?([\d+-.]+)(.*)$/),start=e.cur(true)||0;if(parts){var end=parseFloat(parts[2]),unit=parts[3]||"px";if(unit!="px"){self.style[name]=(end||1)+unit;start=((end||1)/e.cur(true))*start;self.style[name]=start+unit}if(parts[1]){end=((parts[1]=="-="?-1:1)*end)+start}e.custom(start,end,unit)}else{e.custom(start,val,"")}}});return true})},stop:function(clearQueue,gotoEnd){var timers=jQuery.timers;if(clearQueue){this.queue([])}this.each(function(){for(var i=timers.length-1;i>=0;i--){if(timers[i].elem==this){if(gotoEnd){timers[i](true)}timers.splice(i,1)}}});if(!gotoEnd){this.dequeue()}return this}});jQuery.each({slideDown:genFx("show",1),slideUp:genFx("hide",1),slideToggle:genFx("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"}},function(name,props){jQuery.fn[name]=function(speed,callback){return this.animate(props,speed,callback)}});jQuery.extend({speed:function(speed,easing,fn){var opt=typeof speed==="object"?speed:{complete:fn||!fn&&easing||jQuery.isFunction(speed)&&speed,duration:speed,easing:fn&&easing||easing&&!jQuery.isFunction(easing)&&easing};opt.duration=jQuery.fx.off?0:typeof opt.duration==="number"?opt.duration:jQuery.fx.speeds[opt.duration]||jQuery.fx.speeds._default;opt.old=opt.complete;opt.complete=function(){if(opt.queue!==false){jQuery(this).dequeue()}if(jQuery.isFunction(opt.old)){opt.old.call(this)}};return opt},easing:{linear:function(p,n,firstNum,diff){return firstNum+diff*p},swing:function(p,n,firstNum,diff){return((-Math.cos(p*Math.PI)/2)+0.5)*diff+firstNum}},timers:[],fx:function(elem,options,prop){this.options=options;this.elem=elem;this.prop=prop;if(!options.orig){options.orig={}}}});jQuery.fx.prototype={update:function(){if(this.options.step){this.options.step.call(this.elem,this.now,this)}(jQuery.fx.step[this.prop]||jQuery.fx.step._default)(this);if((this.prop=="height"||this.prop=="width")&&this.elem.style){this.elem.style.display="block"}},cur:function(force){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null)){return this.elem[this.prop]}var r=parseFloat(jQuery.css(this.elem,this.prop,force));return r&&r>-10000?r:parseFloat(jQuery.curCSS(this.elem,this.prop))||0},custom:function(from,to,unit){this.startTime=now();this.start=from;this.end=to;this.unit=unit||this.unit||"px";this.now=this.start;this.pos=this.state=0;var self=this;function t(gotoEnd){return self.step(gotoEnd)}t.elem=this.elem;if(t()&&jQuery.timers.push(t)&&!timerId){timerId=setInterval(function(){var timers=jQuery.timers;for(var i=0;i<timers.length;i++){if(!timers[i]()){timers.splice(i--,1)}}if(!timers.length){clearInterval(timerId);timerId=undefined}},13)}},show:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.show=true;this.custom(this.prop=="width"||this.prop=="height"?1:0,this.cur());jQuery(this.elem).show()},hide:function(){this.options.orig[this.prop]=jQuery.attr(this.elem.style,this.prop);this.options.hide=true;this.custom(this.cur(),0)},step:function(gotoEnd){var t=now();if(gotoEnd||t>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;var done=true;for(var i in this.options.curAnim){if(this.options.curAnim[i]!==true){done=false}}if(done){if(this.options.display!=null){this.elem.style.overflow=this.options.overflow;this.elem.style.display=this.options.display;if(jQuery.css(this.elem,"display")=="none"){this.elem.style.display="block"}}if(this.options.hide){jQuery(this.elem).hide()}if(this.options.hide||this.options.show){for(var p in this.options.curAnim){jQuery.attr(this.elem.style,p,this.options.orig[p])}}this.options.complete.call(this.elem)}return false}else{var n=t-this.startTime;this.state=n/this.options.duration;this.pos=jQuery.easing[this.options.easing||(jQuery.easing.swing?"swing":"linear")](this.state,n,0,1,this.options.duration);this.now=this.start+((this.end-this.start)*this.pos);this.update()}return true}};jQuery.extend(jQuery.fx,{speeds:{slow:600,fast:200,_default:400},step:{opacity:function(fx){jQuery.attr(fx.elem.style,"opacity",fx.now)},_default:function(fx){if(fx.elem.style&&fx.elem.style[fx.prop]!=null){fx.elem.style[fx.prop]=fx.now+fx.unit}else{fx.elem[fx.prop]=fx.now}}}});if(document.documentElement.getBoundingClientRect){jQuery.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return jQuery.offset.bodyOffset(this[0])}var box=this[0].getBoundingClientRect(),doc=this[0].ownerDocument,body=doc.body,docElem=doc.documentElement,clientTop=docElem.clientTop||body.clientTop||0,clientLeft=docElem.clientLeft||body.clientLeft||0,top=box.top+(self.pageYOffset||jQuery.boxModel&&docElem.scrollTop||body.scrollTop)-clientTop,left=box.left+(self.pageXOffset||jQuery.boxModel&&docElem.scrollLeft||body.scrollLeft)-clientLeft;return{top:top,left:left}}}else{jQuery.fn.offset=function(){if(!this[0]){return{top:0,left:0}}if(this[0]===this[0].ownerDocument.body){return jQuery.offset.bodyOffset(this[0])}jQuery.offset.initialized||jQuery.offset.initialize();var elem=this[0],offsetParent=elem.offsetParent,prevOffsetParent=elem,doc=elem.ownerDocument,computedStyle,docElem=doc.documentElement,body=doc.body,defaultView=doc.defaultView,prevComputedStyle=defaultView.getComputedStyle(elem,null),top=elem.offsetTop,left=elem.offsetLeft;while((elem=elem.parentNode)&&elem!==body&&elem!==docElem){computedStyle=defaultView.getComputedStyle(elem,null);top-=elem.scrollTop,left-=elem.scrollLeft;if(elem===offsetParent){top+=elem.offsetTop,left+=elem.offsetLeft;if(jQuery.offset.doesNotAddBorder&&!(jQuery.offset.doesAddBorderForTableAndCells&&/^t(able|d|h)$/i.test(elem.tagName))){top+=parseInt(computedStyle.borderTopWidth,10)||0,left+=parseInt(computedStyle.borderLeftWidth,10)||0}prevOffsetParent=offsetParent,offsetParent=elem.offsetParent}if(jQuery.offset.subtractsBorderForOverflowNotVisible&&computedStyle.overflow!=="visible"){top+=parseInt(computedStyle.borderTopWidth,10)||0,left+=parseInt(computedStyle.borderLeftWidth,10)||0}prevComputedStyle=computedStyle}if(prevComputedStyle.position==="relative"||prevComputedStyle.position==="static"){top+=body.offsetTop,left+=body.offsetLeft}if(prevComputedStyle.position==="fixed"){top+=Math.max(docElem.scrollTop,body.scrollTop),left+=Math.max(docElem.scrollLeft,body.scrollLeft)}return{top:top,left:left}}}jQuery.offset={initialize:function(){if(this.initialized){return }var body=document.body,container=document.createElement("div"),innerDiv,checkDiv,table,td,rules,prop,bodyMarginTop=body.style.marginTop,html='<div style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;"><div></div></div><table style="position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;" cellpadding="0" cellspacing="0"><tr><td></td></tr></table>';rules={position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",height:"1px",visibility:"hidden"};for(prop in rules){container.style[prop]=rules[prop]}container.innerHTML=html;body.insertBefore(container,body.firstChild);innerDiv=container.firstChild,checkDiv=innerDiv.firstChild,td=innerDiv.nextSibling.firstChild.firstChild;this.doesNotAddBorder=(checkDiv.offsetTop!==5);this.doesAddBorderForTableAndCells=(td.offsetTop===5);innerDiv.style.overflow="hidden",innerDiv.style.position="relative";this.subtractsBorderForOverflowNotVisible=(checkDiv.offsetTop===-5);body.style.marginTop="1px";this.doesNotIncludeMarginInBodyOffset=(body.offsetTop===0);body.style.marginTop=bodyMarginTop;body.removeChild(container);this.initialized=true},bodyOffset:function(body){jQuery.offset.initialized||jQuery.offset.initialize();var top=body.offsetTop,left=body.offsetLeft;if(jQuery.offset.doesNotIncludeMarginInBodyOffset){top+=parseInt(jQuery.curCSS(body,"marginTop",true),10)||0,left+=parseInt(jQuery.curCSS(body,"marginLeft",true),10)||0}return{top:top,left:left}}};jQuery.fn.extend({position:function(){var left=0,top=0,results;if(this[0]){var offsetParent=this.offsetParent(),offset=this.offset(),parentOffset=/^body|html$/i.test(offsetParent[0].tagName)?{top:0,left:0}:offsetParent.offset();offset.top-=num(this,"marginTop");offset.left-=num(this,"marginLeft");parentOffset.top+=num(offsetParent,"borderTopWidth");parentOffset.left+=num(offsetParent,"borderLeftWidth");results={top:offset.top-parentOffset.top,left:offset.left-parentOffset.left}}return results},offsetParent:function(){var offsetParent=this[0].offsetParent||document.body;while(offsetParent&&(!/^body|html$/i.test(offsetParent.tagName)&&jQuery.css(offsetParent,"position")=="static")){offsetParent=offsetParent.offsetParent}return jQuery(offsetParent)}});jQuery.each(["Left","Top"],function(i,name){var method="scroll"+name;jQuery.fn[method]=function(val){if(!this[0]){return null}return val!==undefined?this.each(function(){this==window||this==document?window.scrollTo(!i?val:jQuery(window).scrollLeft(),i?val:jQuery(window).scrollTop()):this[method]=val}):this[0]==window||this[0]==document?self[i?"pageYOffset":"pageXOffset"]||jQuery.boxModel&&document.documentElement[method]||document.body[method]:this[0][method]}});jQuery.each(["Height","Width"],function(i,name){var tl=i?"Left":"Top",br=i?"Right":"Bottom",lower=name.toLowerCase();jQuery.fn["inner"+name]=function(){return this[0]?jQuery.css(this[0],lower,false,"padding"):null};jQuery.fn["outer"+name]=function(margin){return this[0]?jQuery.css(this[0],lower,false,margin?"margin":"border"):null};var type=name.toLowerCase();jQuery.fn[type]=function(size){return this[0]==window?document.compatMode=="CSS1Compat"&&document.documentElement["client"+name]||document.body["client"+name]:this[0]==document?Math.max(document.documentElement["client"+name],document.body["scroll"+name],document.documentElement["scroll"+name],document.body["offset"+name],document.documentElement["offset"+name]):size===undefined?(this.length?jQuery.css(this[0],type):null):this.css(type,typeof size==="string"?size:size+"px")}})})();
@@ -1,13 +1,25 @@
1
+ .vanity .description { padding: 0; margin: 0 0 .6em 0; color: #666 }
2
+ .vanity .meta { color: #666 }
3
+ .vanity .footer { margin-top: 2em; text-align: right; font-size: 90% }
4
+ .vanity h2, .vanity h3 { margin: 0 0 .3em 0 }
5
+
1
6
  .vanity .experiments { list-style: none; margin: 0; padding: 0 }
2
- .vanity .experiment { padding-bottom: 1em; margin: 0 0 1em 0; border-bottom: 1px dashed #ddd }
3
- .vanity .experiment .description { padding: .5em; margin: 0 }
7
+ .vanity .experiment { margin: 1em 0 2em 0; border-bottom: 1px solid #ddd }
4
8
  .vanity .experiment .type { margin-left: .3em; color: #bbb; font-size: .8em; font-weight: normal }
5
- .vanity .experiment .meta { color: #444; font-style: italic }
6
9
 
7
10
  .vanity .ab_test table { border-collapse: collapse; table-layout: fixed; width: 100%; border-bottom: 1px solid #ccc; margin: 1em 0 0 0 }
8
11
  .vanity .ab_test td { padding: .5em; border-top: 1px solid #ccc }
9
12
  .vanity .ab_test .choice td { font-weight: bold; background: #f0f0f8 }
10
- .vanity .ab_test caption { caption-side: bottom; padding: .5em; background: transparent; margin-bottom: 1em; text-align: left }
13
+ .vanity .ab_test caption { caption-side: bottom; padding: .5em; background: transparent; text-align: left }
11
14
  .vanity .ab_test td.option { width: 5em; white-space: nowrap; overflow: hidden }
12
15
  .vanity .ab_test td.value { width: 8em; white-space: nowrap; overflow: hidden }
13
16
  .vanity .ab_test td.action { width: 6em; overflow: hidden; text-align: center }
17
+
18
+ .vanity .metrics { list-style: none; margin: 0; padding: 0; border-bottom: 1px solid #ddd }
19
+ .vanity .metric { margin: 2em 0 }
20
+ .vanity .metric .chart { width:100%; margin: .6em 0 }
21
+ .vanity .metric .legend { float: left; width:20%; padding-right: 1em; overflow: hidden }
22
+ .vanity form#milestones { margin: 1em 0 }
23
+ .vanity form#milestones label { margin-right: .5em }
24
+ .vanity form#milestones input { vertical-align: bottom }
25
+ .vanity .metric .marking.label { position: absolute; bottom: 2em; color: #c66; font-size: 80% }
@@ -0,0 +1,96 @@
1
+ var Vanity = {}
2
+ Vanity.tooltip = function(event, pos, item) {
3
+ if (item) {
4
+ if (this.previousPoint != item.datapoint) {
5
+ this.previousPoint = item.datapoint;
6
+ $("#tooltip").remove();
7
+ var x = item.datapoint[0].toFixed(2), y = item.datapoint[1].toFixed(2);
8
+ $('<div id="tooltip">' + new Date(parseInt(x, 10)).toDateString() + "&mdash;" + y + '</div>').css( {
9
+ position: 'absolute', display: 'none',
10
+ top: item.pageY + 5, left: item.pageX + 5,
11
+ padding: '2px', border: '1px solid #ff8', 'background-color': '#ffe', opacity: 0.9
12
+ }).appendTo("body").fadeIn(200);
13
+ }
14
+ } else {
15
+ $("#tooltip").remove();
16
+ this.previousPoint = null;
17
+ }
18
+ }
19
+
20
+ Vanity.metric = function(id) {
21
+ var metric = {};
22
+ metric.chart = $("#metric_" + id + " .chart");
23
+ metric.chart.height(metric.chart.width() / 7);
24
+ metric.markings = [];
25
+ metric.options = {
26
+ xaxis: { mode: "time", minTickSize: [7, "day"] },
27
+ yaxis: { ticks: [0, 100], autoscaleMargin: null },
28
+ series: { lines: { show: true, lineWidth: 2, fill: true, fillColor: { colors: ["#fff", "#C6D2DA"] } },
29
+ points: { show: false, radius: 1 }, shadowSize: 0 },
30
+ colors: ["#0077CC"],
31
+ legend: { position: 'sw', container: "#metric_" + id +" .legend", backgroundOpacity: 0.5 },
32
+ grid: { markings: metric.markings, borderWidth: 1, borderColor: '#eee', hoverable: true, aboveData: true } };
33
+
34
+ metric.mark = function(start, end, label) {
35
+ metric.markings.push({color: "#f02020", xaxis: { from: start, to: start + 4 * 3600 * 1000 }, text: label});
36
+ metric.markings.push({color: "#f02020", xaxis: { from: end, to: end + 4 * 3600 * 1000 }});
37
+ }
38
+ metric.plot = function(lines) {
39
+ var min, max;
40
+ $.each(lines[0].data, function(i, val) { var y = val[1];
41
+ if (max == null || y > max) max = y;
42
+ if (min == null || y < min) min = y;
43
+ });
44
+ if (min == null) min = max = 0;
45
+ metric.options.yaxis.ticks = [min, (min + max) / 2.0, max];
46
+ var plot = $.plot(metric.chart, lines, metric.options);
47
+ $.each(metric.markings, function(i, mark) {
48
+ if (mark.xaxis && mark.xaxis.from && mark.label) {
49
+ var o = plot.pointOffset({x:mark.xaxis.from, y:max / 10 - min});
50
+ $('<div style="position:absolute;bottom:2em;color:#f02020;font-size:80%"></div>').
51
+ css({left:o.left+4, top:o.top-4}).text(mark.text).appendTo(metric.chart);
52
+ }
53
+ });
54
+ metric.chart.bind("plothover", Vanity.tooltip);
55
+ metric.chart.data('plot', plot);
56
+ }
57
+ return metric;
58
+ }
59
+
60
+ $(function() {
61
+ var checkboxes = $("#milestones input:checkbox");
62
+ checkboxes.bind("change", function() {
63
+ var markings = [];
64
+ checkboxes.filter(":checked").each(function(i, checkbox) {
65
+ var start = parseInt($(this).attr("data-start"), 10) * 1000;
66
+ var end = parseInt($(this).attr("data-end"), 10) * 1000;
67
+ var title = $(this).parent().text();
68
+ markings.push({color: "#c66", xaxis: { from: start - 20000000, to: start }, label: title});
69
+ if (end > start)
70
+ markings.push({color: "#c99", xaxis: { from: end, to: end + 20000000 }});
71
+ });
72
+ $(".metric .marking.label").remove();
73
+ $(".metric .chart").each(function() {
74
+ var chart = $(this);
75
+ var plot = chart.data('plot');
76
+ plot.getOptions().grid.markings = markings;
77
+ plot.draw();
78
+ $.each(markings, function(i, mark) {
79
+ if (mark.xaxis && mark.xaxis.from && mark.label) {
80
+ var o = plot.pointOffset({x:mark.xaxis.from});
81
+ $('<div class="marking label"></div>').css({left:o.left+4}).text(mark.label).appendTo(chart);
82
+ }
83
+ });
84
+ });
85
+ });
86
+
87
+ $(".experiment.ab_test a.button.chooses").live("click", function() {
88
+ var link = $(this);
89
+ $.ajax({
90
+ data: 'authenticity_token=' + encodeURIComponent(document.auth_token),
91
+ success: function(request){ $('#experiment_' + link.attr("data-id")).html(request) },
92
+ url: link.attr("data-url"), type: 'post'
93
+ });
94
+ return false;
95
+ });
96
+ });
data/test/ab_test_test.rb CHANGED
@@ -5,20 +5,20 @@ class AbTestController < ActionController::Base
5
5
  attr_accessor :current_user
6
6
 
7
7
  def test_render
8
- render text: ab_test(:simple)
8
+ render :text=>ab_test(:simple)
9
9
  end
10
10
 
11
11
  def test_view
12
- render inline: "<%= ab_test(:simple) %>"
12
+ render :inline=>"<%= ab_test(:simple) %>"
13
13
  end
14
14
 
15
15
  def test_capture
16
- render inline: "<% ab_test :simple do |value| %><%= value %><% end %>"
16
+ render :inline=>"<% ab_test :simple do |value| %><%= value %><% end %>"
17
17
  end
18
18
 
19
19
  def track
20
- track! :simple
21
- render text: ""
20
+ track! :coolness
21
+ render :text=>""
22
22
  end
23
23
  end
24
24
 
@@ -26,6 +26,11 @@ end
26
26
  class AbTestTest < ActionController::TestCase
27
27
  tests AbTestController
28
28
 
29
+ def setup
30
+ super
31
+ metric "Coolness"
32
+ end
33
+
29
34
  # -- Experiment definition --
30
35
 
31
36
  def test_requires_at_least_two_alternatives_per_experiment
@@ -41,12 +46,14 @@ class AbTestTest < ActionController::TestCase
41
46
  end
42
47
  ab_test :two do
43
48
  alternatives "foo", "bar"
49
+ metrics :coolness
44
50
  end
45
51
  end
46
52
 
47
53
  def test_returning_alternative_by_value
48
54
  ab_test :abcd do
49
55
  alternatives :a, :b, :c, :d
56
+ metrics :coolness
50
57
  end
51
58
  assert_equal experiment(:abcd).alternatives[1], experiment(:abcd).alternative(:b)
52
59
  assert_equal experiment(:abcd).alternatives[3], experiment(:abcd).alternative(:d)
@@ -55,18 +62,45 @@ class AbTestTest < ActionController::TestCase
55
62
  def test_alternative_name
56
63
  ab_test :abcd do
57
64
  alternatives :a, :b
65
+ metrics :coolness
58
66
  end
59
67
  assert_equal "option A", experiment(:abcd).alternative(:a).name
60
68
  assert_equal "option B", experiment(:abcd).alternative(:b).name
61
69
  end
62
70
 
63
71
 
72
+ # -- Experiment metric --
73
+
74
+ def test_explicit_metric
75
+ ab_test :abcd do
76
+ metrics :coolness
77
+ end
78
+ assert_equal [Vanity.playground.metric(:coolness)], experiment(:abcd).metrics
79
+ end
80
+
81
+ def test_implicit_metric
82
+ ab_test :abcd do
83
+ end
84
+ assert_equal [Vanity.playground.metric(:abcd)], experiment(:abcd).metrics
85
+ end
86
+
87
+ def test_metric_tracking_into_alternative
88
+ metric "Coolness"
89
+ ab_test :abcd do
90
+ metrics :coolness
91
+ end
92
+ Vanity.playground.track! :coolness
93
+ assert_equal 1, experiment(:abcd).alternatives.sum(&:conversions)
94
+ end
95
+
96
+
64
97
  # -- Running experiment --
65
98
 
66
99
  def test_returns_the_same_alternative_consistently
67
100
  ab_test :foobar do
68
101
  alternatives "foo", "bar"
69
102
  identify { "6e98ec" }
103
+ metrics :coolness
70
104
  end
71
105
  assert value = experiment(:foobar).choose
72
106
  assert_match /foo|bar/, value
@@ -79,10 +113,11 @@ class AbTestTest < ActionController::TestCase
79
113
  ab_test :foobar do
80
114
  alternatives "foo", "bar"
81
115
  identify { rand }
116
+ metrics :coolness
82
117
  end
83
118
  alts = Array.new(1000) { experiment(:foobar).choose }
84
119
  assert_equal %w{bar foo}, alts.uniq.sort
85
- assert_in_delta alts.select { |a| a == "foo" }.count, 500, 100 # this may fail, such is propability
120
+ assert_in_delta alts.select { |a| a == "foo" }.size, 500, 100 # this may fail, such is propability
86
121
  end
87
122
 
88
123
  def test_records_all_participants_in_each_alternative
@@ -90,6 +125,7 @@ class AbTestTest < ActionController::TestCase
90
125
  ab_test :foobar do
91
126
  alternatives "foo", "bar"
92
127
  identify { ids.pop }
128
+ metrics :coolness
93
129
  end
94
130
  1000.times { experiment(:foobar).choose }
95
131
  alts = experiment(:foobar).alternatives
@@ -102,10 +138,11 @@ class AbTestTest < ActionController::TestCase
102
138
  ab_test :foobar do
103
139
  alternatives "foo", "bar"
104
140
  identify { ids.pop }
141
+ metrics :coolness
105
142
  end
106
143
  500.times do
107
144
  experiment(:foobar).choose
108
- experiment(:foobar).track!
145
+ metric(:coolness).track!
109
146
  end
110
147
  alts = experiment(:foobar).alternatives
111
148
  assert_equal 100, alts.map(&:converted).sum
@@ -116,25 +153,28 @@ class AbTestTest < ActionController::TestCase
116
153
  ab_test :foobar do
117
154
  alternatives "foo", "bar"
118
155
  identify { ids.pop }
156
+ metrics :coolness
119
157
  end
120
158
  500.times do
121
159
  experiment(:foobar).choose
122
- experiment(:foobar).track!
123
- experiment(:foobar).track!
160
+ metric(:coolness).track!
161
+ metric(:coolness).track!
124
162
  end
125
163
  alts = experiment(:foobar).alternatives
126
164
  assert_equal 100, alts.map(&:converted).sum
127
165
  end
128
166
 
167
+
129
168
  def test_destroy_experiment
130
169
  ab_test :simple do
131
170
  identify { "me" }
171
+ metrics :coolness
132
172
  complete_if { alternatives.map(&:converted).sum >= 1 }
133
173
  outcome_is { alternative(true) }
134
174
  end
135
175
  experiment(:simple).choose
136
- experiment(:simple).track!
137
- refute experiment(:simple).active?
176
+ metric(:coolness).track!
177
+ assert !experiment(:simple).active?
138
178
  assert_equal true, experiment(:simple).outcome.value
139
179
 
140
180
  experiment(:simple).destroy
@@ -150,13 +190,15 @@ class AbTestTest < ActionController::TestCase
150
190
  # -- A/B helper methods --
151
191
 
152
192
  def test_fail_if_no_experiment
153
- assert_raise LoadError do
193
+ assert_raise NameError do
154
194
  get :test_render
155
195
  end
156
196
  end
157
197
 
158
198
  def test_ab_test_chooses_in_render
159
- ab_test(:simple) { }
199
+ ab_test :simple do
200
+ metrics :coolness
201
+ end
160
202
  responses = Array.new(100) do
161
203
  @controller = nil ; setup_controller_request_and_response
162
204
  get :test_render
@@ -166,7 +208,9 @@ class AbTestTest < ActionController::TestCase
166
208
  end
167
209
 
168
210
  def test_ab_test_chooses_view_helper
169
- ab_test(:simple) { }
211
+ ab_test :simple do
212
+ metrics :coolness
213
+ end
170
214
  responses = Array.new(100) do
171
215
  @controller = nil ; setup_controller_request_and_response
172
216
  get :test_view
@@ -176,7 +220,9 @@ class AbTestTest < ActionController::TestCase
176
220
  end
177
221
 
178
222
  def test_ab_test_with_capture
179
- ab_test(:simple) { }
223
+ ab_test :simple do
224
+ metrics :coolness
225
+ end
180
226
  responses = Array.new(100) do
181
227
  @controller = nil ; setup_controller_request_and_response
182
228
  get :test_capture
@@ -186,7 +232,9 @@ class AbTestTest < ActionController::TestCase
186
232
  end
187
233
 
188
234
  def test_ab_test_track
189
- ab_test(:simple) { }
235
+ ab_test :simple do
236
+ metrics :coolness
237
+ end
190
238
  responses = Array.new(100) do
191
239
  @controller.send(:cookies).clear
192
240
  get :track
@@ -198,7 +246,10 @@ class AbTestTest < ActionController::TestCase
198
246
  # -- Testing with tests --
199
247
 
200
248
  def test_with_given_choice
201
- ab_test(:simple) { alternatives :a, :b, :c }
249
+ ab_test :simple do
250
+ alternatives :a, :b, :c
251
+ metrics :coolness
252
+ end
202
253
  100.times do |i|
203
254
  @controller = nil ; setup_controller_request_and_response
204
255
  experiment(:simple).chooses(:b)
@@ -208,7 +259,9 @@ class AbTestTest < ActionController::TestCase
208
259
  end
209
260
 
210
261
  def test_which_chooses_non_existent_alternative
211
- ab_test(:simple) { }
262
+ ab_test :simple do
263
+ metrics :coolness
264
+ end
212
265
  assert_raises ArgumentError do
213
266
  experiment(:simple).chooses(404)
214
267
  end
@@ -218,6 +271,7 @@ class AbTestTest < ActionController::TestCase
218
271
  ab_test :simple do
219
272
  identify { rand }
220
273
  alternatives :a, :b, :c
274
+ metrics :coolness
221
275
  end
222
276
  responses = Array.new(100) { |i|
223
277
  @controller = nil ; setup_controller_request_and_response
@@ -231,22 +285,18 @@ class AbTestTest < ActionController::TestCase
231
285
 
232
286
 
233
287
  # -- Scoring --
234
-
288
+
235
289
  def test_scoring
236
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
290
+ ab_test :abcd do
291
+ alternatives :a, :b, :c, :d
292
+ metrics :coolness
293
+ end
237
294
  # participating, conversions, rate, z-score
238
295
  # Control: 182 35 19.23% N/A
239
- 182.times { |i| experiment(:abcd).send(:count_participant, i, :a) }
240
- 35.times { |i| experiment(:abcd).send(:count_conversion, i, :a) }
241
296
  # Treatment A: 180 45 25.00% 1.33
242
- 180.times { |i| experiment(:abcd).send(:count_participant, i, :b) }
243
- 45.times { |i| experiment(:abcd).send(:count_conversion, i, :b) }
244
297
  # treatment B: 189 28 14.81% -1.13
245
- 189.times { |i| experiment(:abcd).send(:count_participant, i, :c) }
246
- 28.times { |i| experiment(:abcd).send(:count_conversion, i, :c) }
247
298
  # treatment C: 188 61 32.45% 2.94
248
- 188.times { |i| experiment(:abcd).send(:count_participant, i, :d) }
249
- 61.times { |i| experiment(:abcd).send(:count_conversion, i, :d) }
299
+ fake :abcd, :a=>[182, 35], :b=>[180, 45], :c=>[189,28], :d=>[188, 61]
250
300
 
251
301
  z_scores = experiment(:abcd).score.alts.map { |alt| "%.2f" % alt.z_score }
252
302
  assert_equal %w{-1.33 0.00 -2.47 1.58}, z_scores
@@ -263,7 +313,10 @@ class AbTestTest < ActionController::TestCase
263
313
  end
264
314
 
265
315
  def test_scoring_with_no_performers
266
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
316
+ ab_test :abcd do
317
+ alternatives :a, :b, :c, :d
318
+ metrics :coolness
319
+ end
267
320
  assert experiment(:abcd).score.alts.all? { |alt| alt.z_score.nan? }
268
321
  assert experiment(:abcd).score.alts.all? { |alt| alt.probability == 0 }
269
322
  assert experiment(:abcd).score.alts.all? { |alt| alt.difference.nil? }
@@ -273,9 +326,11 @@ class AbTestTest < ActionController::TestCase
273
326
  end
274
327
 
275
328
  def test_scoring_with_one_performer
276
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
277
- 10.times { |i| experiment(:abcd).send(:count_participant, i, :b) }
278
- 8.times { |i| experiment(:abcd).send(:count_conversion, i, :b) }
329
+ ab_test :abcd do
330
+ alternatives :a, :b, :c, :d
331
+ metrics :coolness
332
+ end
333
+ fake :abcd, :b=>[10,8]
279
334
  assert experiment(:abcd).score.alts.all? { |alt| alt.z_score.nan? }
280
335
  assert experiment(:abcd).score.alts.all? { |alt| alt.probability == 0 }
281
336
  assert experiment(:abcd).score.alts.all? { |alt| alt.difference.nil? }
@@ -286,14 +341,14 @@ class AbTestTest < ActionController::TestCase
286
341
  end
287
342
 
288
343
  def test_scoring_with_some_performers
289
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
290
- 10.times { |i| experiment(:abcd).send(:count_participant, i, :b) }
291
- 8.times { |i| experiment(:abcd).send(:count_conversion, i, :b) }
292
- 12.times { |i| experiment(:abcd).send(:count_participant, i, :d) }
293
- 5.times { |i| experiment(:abcd).send(:count_conversion, i, :d) }
344
+ ab_test :abcd do
345
+ alternatives :a, :b, :c, :d
346
+ metrics :coolness
347
+ end
348
+ fake :abcd, :b=>[10,8], :d=>[12,5]
294
349
 
295
- z_scores = experiment(:abcd).score.alts.map { |alt| "%.2f" % alt.z_score }
296
- assert_equal %w{NaN 2.01 NaN 0.00}, z_scores
350
+ z_scores = experiment(:abcd).score.alts.map { |alt| "%.2f" % alt.z_score }.map(&:downcase)
351
+ assert_equal %w{nan 2.01 nan 0.00}, z_scores
297
352
  probabilities = experiment(:abcd).score.alts.map(&:probability)
298
353
  assert_equal [0, 95, 0, 0], probabilities
299
354
  diff = experiment(:abcd).score.alts.map { |alt| alt.difference && alt.difference.round }
@@ -305,11 +360,11 @@ class AbTestTest < ActionController::TestCase
305
360
  end
306
361
 
307
362
  def test_scoring_with_different_probability
308
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
309
- 10.times { |i| experiment(:abcd).send(:count_participant, i, :b) }
310
- 8.times { |i| experiment(:abcd).send(:count_conversion, i, :b) }
311
- 12.times { |i| experiment(:abcd).send(:count_participant, i, :d) }
312
- 5.times { |i| experiment(:abcd).send(:count_conversion, i, :d) }
363
+ ab_test :abcd do
364
+ alternatives :a, :b, :c, :d
365
+ metrics :coolness
366
+ end
367
+ fake :abcd, :b=>[10,8], :d=>[12,5]
313
368
 
314
369
  assert_equal 1, experiment(:abcd).score(90).choice.id
315
370
  assert_equal 1, experiment(:abcd).score(95).choice.id
@@ -320,20 +375,16 @@ class AbTestTest < ActionController::TestCase
320
375
  # -- Conclusion --
321
376
 
322
377
  def test_conclusion
323
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
378
+ ab_test :abcd do
379
+ alternatives :a, :b, :c, :d
380
+ metrics :coolness
381
+ end
324
382
  # participating, conversions, rate, z-score
325
383
  # Control: 182 35 19.23% N/A
326
- 182.times { |i| experiment(:abcd).send(:count_participant, i, :a) }
327
- 35.times { |i| experiment(:abcd).send(:count_conversion, i, :a) }
328
384
  # Treatment A: 180 45 25.00% 1.33
329
- 180.times { |i| experiment(:abcd).send(:count_participant, i, :b) }
330
- 45.times { |i| experiment(:abcd).send(:count_conversion, i, :b) }
331
385
  # treatment B: 189 28 14.81% -1.13
332
- 189.times { |i| experiment(:abcd).send(:count_participant, i, :c) }
333
- 28.times { |i| experiment(:abcd).send(:count_conversion, i, :c) }
334
386
  # treatment C: 188 61 32.45% 2.94
335
- 188.times { |i| experiment(:abcd).send(:count_participant, i, :d) }
336
- 61.times { |i| experiment(:abcd).send(:count_conversion, i, :d) }
387
+ fake :abcd, :a=>[182, 35], :b=>[180, 45], :c=>[189,28], :d=>[188, 61]
337
388
 
338
389
  assert_equal <<-TEXT, experiment(:abcd).conclusion.join("\n") << "\n"
339
390
  There are 739 participants in this experiment.
@@ -347,13 +398,11 @@ Option D selected as the best alternative.
347
398
  end
348
399
 
349
400
  def test_conclusion_with_some_performers
350
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
351
- # Treatment A: 180 45 25.00% 1.33
352
- 180.times { |i| experiment(:abcd).send(:count_participant, i, :b) }
353
- 45.times { |i| experiment(:abcd).send(:count_conversion, i, :b) }
354
- # treatment C: 188 61 32.45% 2.94
355
- 188.times { |i| experiment(:abcd).send(:count_participant, i, :d) }
356
- 61.times { |i| experiment(:abcd).send(:count_conversion, i, :d) }
401
+ ab_test :abcd do
402
+ alternatives :a, :b, :c, :d
403
+ metrics :coolness
404
+ end
405
+ fake :abcd, :b=>[180, 45], :d=>[188, 61]
357
406
 
358
407
  assert_equal <<-TEXT, experiment(:abcd).conclusion.join("\n") << "\n"
359
408
  There are 368 participants in this experiment.
@@ -367,13 +416,11 @@ Option D selected as the best alternative.
367
416
  end
368
417
 
369
418
  def test_conclusion_without_clear_winner
370
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
371
- # Treatment A: 180 45 25.00% 1.33
372
- 180.times { |i| experiment(:abcd).send(:count_participant, i, :b) }
373
- 58.times { |i| experiment(:abcd).send(:count_conversion, i, :b) }
374
- # treatment C: 188 61 32.45% 2.94
375
- 188.times { |i| experiment(:abcd).send(:count_participant, i, :d) }
376
- 61.times { |i| experiment(:abcd).send(:count_conversion, i, :d) }
419
+ ab_test :abcd do
420
+ alternatives :a, :b, :c, :d
421
+ metrics :coolness
422
+ end
423
+ fake :abcd, :b=>[180, 58], :d=>[188, 61]
377
424
 
378
425
  assert_equal <<-TEXT, experiment(:abcd).conclusion.join("\n") << "\n"
379
426
  There are 368 participants in this experiment.
@@ -386,13 +433,11 @@ Option C did not convert.
386
433
  end
387
434
 
388
435
  def test_conclusion_without_close_performers
389
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
390
- # Treatment A: 180 45 25.00% 1.33
391
- 186.times { |i| experiment(:abcd).send(:count_participant, i, :b) }
392
- 60.times { |i| experiment(:abcd).send(:count_conversion, i, :b) }
393
- # treatment C: 188 61 32.45% 2.94
394
- 188.times { |i| experiment(:abcd).send(:count_participant, i, :d) }
395
- 61.times { |i| experiment(:abcd).send(:count_conversion, i, :d) }
436
+ ab_test :abcd do
437
+ alternatives :a, :b, :c, :d
438
+ metrics :coolness
439
+ end
440
+ fake :abcd, :b=>[186, 60], :d=>[188, 61]
396
441
 
397
442
  assert_equal <<-TEXT, experiment(:abcd).conclusion.join("\n") << "\n"
398
443
  There are 374 participants in this experiment.
@@ -405,13 +450,11 @@ Option C did not convert.
405
450
  end
406
451
 
407
452
  def test_conclusion_without_equal_performers
408
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
409
- # Treatment A: 180 45 25.00% 1.33
410
- 188.times { |i| experiment(:abcd).send(:count_participant, i, :b) }
411
- 61.times { |i| experiment(:abcd).send(:count_conversion, i, :b) }
412
- # treatment C: 188 61 32.45% 2.94
413
- 188.times { |i| experiment(:abcd).send(:count_participant, i, :d) }
414
- 61.times { |i| experiment(:abcd).send(:count_conversion, i, :d) }
453
+ ab_test :abcd do
454
+ alternatives :a, :b, :c, :d
455
+ metrics :coolness
456
+ end
457
+ fake :abcd, :b=>[188, 61], :d=>[188, 61]
415
458
 
416
459
  assert_equal <<-TEXT, experiment(:abcd).conclusion.join("\n") << "\n"
417
460
  There are 376 participants in this experiment.
@@ -423,10 +466,11 @@ Option C did not convert.
423
466
  end
424
467
 
425
468
  def test_conclusion_with_one_performers
426
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
427
- # Treatment A: 180 45 25.00% 1.33
428
- 180.times { |i| experiment(:abcd).send(:count_participant, i, :b) }
429
- 45.times { |i| experiment(:abcd).send(:count_conversion, i, :b) }
469
+ ab_test :abcd do
470
+ alternatives :a, :b, :c, :d
471
+ metrics :coolness
472
+ end
473
+ fake :abcd, :b=>[180, 45]
430
474
 
431
475
  assert_equal <<-TEXT, experiment(:abcd).conclusion.join("\n") << "\n"
432
476
  There are 180 participants in this experiment.
@@ -435,7 +479,10 @@ This experiment did not run long enough to find a clear winner.
435
479
  end
436
480
 
437
481
  def test_conclusion_with_no_performers
438
- ab_test(:abcd) { alternatives :a, :b, :c, :d }
482
+ ab_test :abcd do
483
+ alternatives :a, :b, :c, :d
484
+ metrics :coolness
485
+ end
439
486
  assert_equal <<-TEXT, experiment(:abcd).conclusion.join("\n") << "\n"
440
487
  There are no participants in this experiment yet.
441
488
  This experiment did not run long enough to find a clear winner.
@@ -449,15 +496,17 @@ This experiment did not run long enough to find a clear winner.
449
496
  ab_test :simple do
450
497
  identify { rand }
451
498
  complete_if { true }
499
+ metrics :coolness
452
500
  end
453
501
  experiment(:simple).choose
454
- refute experiment(:simple).active?
502
+ assert !experiment(:simple).active?
455
503
  end
456
504
 
457
505
  def test_completion_if_fails
458
506
  ab_test :simple do
459
507
  identify { rand }
460
508
  complete_if { fail }
509
+ metrics :coolness
461
510
  end
462
511
  experiment(:simple).choose
463
512
  assert experiment(:simple).active?
@@ -468,6 +517,7 @@ This experiment did not run long enough to find a clear winner.
468
517
  ab_test :simple do
469
518
  identify { ids.pop }
470
519
  complete_if { alternatives.map(&:participants).sum >= 100 }
520
+ metrics :coolness
471
521
  end
472
522
  99.times do |i|
473
523
  experiment(:simple).choose
@@ -475,7 +525,7 @@ This experiment did not run long enough to find a clear winner.
475
525
  end
476
526
 
477
527
  experiment(:simple).choose
478
- refute experiment(:simple).active?
528
+ assert !experiment(:simple).active?
479
529
  end
480
530
 
481
531
  def test_ab_methods_after_completion
@@ -484,20 +534,21 @@ This experiment did not run long enough to find a clear winner.
484
534
  identify { ids.pop }
485
535
  complete_if { alternatives.map(&:participants).sum >= 100 }
486
536
  outcome_is { alternatives[1] }
537
+ metrics :coolness
487
538
  end
488
539
  # Run experiment to completion (100 participants)
489
540
  results = Set.new
490
541
  100.times do
491
542
  results << experiment(:simple).choose
492
- experiment(:simple).track!
543
+ metric(:coolness).track!
493
544
  end
494
545
  assert results.include?(true) && results.include?(false)
495
- refute experiment(:simple).active?
546
+ assert !experiment(:simple).active?
496
547
 
497
548
  # Test that we always get the same choice (true)
498
549
  100.times do
499
550
  assert_equal true, experiment(:simple).choose
500
- experiment(:simple).track!
551
+ metric(:coolness).track!
501
552
  end
502
553
  # We don't get to count the 100 participant's conversion, but that's ok.
503
554
  assert_equal 99, experiment(:simple).alternatives.map(&:converted).sum
@@ -510,6 +561,7 @@ This experiment did not run long enough to find a clear winner.
510
561
  def test_completion_outcome
511
562
  ab_test :quick do
512
563
  outcome_is { alternatives[1] }
564
+ metrics :coolness
513
565
  end
514
566
  experiment(:quick).complete!
515
567
  assert_equal experiment(:quick).alternatives[1], experiment(:quick).outcome
@@ -518,6 +570,7 @@ This experiment did not run long enough to find a clear winner.
518
570
  def test_outcome_is_returns_nil
519
571
  ab_test :quick do
520
572
  outcome_is { nil }
573
+ metrics :coolness
521
574
  end
522
575
  experiment(:quick).complete!
523
576
  assert_equal experiment(:quick).alternatives.first, experiment(:quick).outcome
@@ -526,6 +579,7 @@ This experiment did not run long enough to find a clear winner.
526
579
  def test_outcome_is_returns_something_else
527
580
  ab_test :quick do
528
581
  outcome_is { "error" }
582
+ metrics :coolness
529
583
  end
530
584
  experiment(:quick).complete!
531
585
  assert_equal experiment(:quick).alternatives.first, experiment(:quick).outcome
@@ -534,6 +588,7 @@ This experiment did not run long enough to find a clear winner.
534
588
  def test_outcome_is_fails
535
589
  ab_test :quick do
536
590
  outcome_is { fail }
591
+ metrics :coolness
537
592
  end
538
593
  experiment(:quick).complete!
539
594
  assert_equal experiment(:quick).alternatives.first, experiment(:quick).outcome
@@ -541,32 +596,40 @@ This experiment did not run long enough to find a clear winner.
541
596
 
542
597
  def test_outcome_choosing_best_alternative
543
598
  ab_test :quick do
599
+ metrics :coolness
544
600
  end
545
- 2.times { |i| experiment(:quick).send(:count_participant, i, false) }
546
- 10.times { |i| experiment(:quick).send(:count_participant, i, true).send(:count_conversion, i, true) }
601
+ fake :quick, false=>[2,0], true=>10
547
602
  experiment(:quick).complete!
548
603
  assert_equal experiment(:quick).alternative(true), experiment(:quick).outcome
549
604
  end
550
605
 
551
606
  def test_outcome_only_performing_alternative
552
607
  ab_test :quick do
608
+ metrics :coolness
553
609
  end
554
- 2.times { |i| experiment(:quick).send(:count_participant, i, true).send(:count_conversion, i, true) }
610
+ fake :quick, true=>2
555
611
  experiment(:quick).complete!
556
612
  assert_equal experiment(:quick).alternative(true), experiment(:quick).outcome
557
613
  end
558
614
 
559
615
  def test_outcome_choosing_equal_alternatives
560
616
  ab_test :quick do
617
+ metrics :coolness
561
618
  end
562
- 8.times { |i| experiment(:quick).send(:count_participant, i, false).send(:count_conversion, i, false) }
563
- 8.times { |i| experiment(:quick).send(:count_participant, i, true). send(:count_conversion, i, true) }
619
+ fake :quick, false=>8, true=>8
564
620
  experiment(:quick).complete!
565
621
  assert_equal experiment(:quick).alternative(true), experiment(:quick).outcome
566
622
  end
567
623
 
568
624
 
625
+ # -- Helper methods --
626
+
569
627
  def ab_test(name, &block)
570
628
  Vanity.playground.define name, :ab_test, &block
571
629
  end
630
+
631
+ def fake(name, args)
632
+ experiment(name).instance_eval { fake args }
633
+ end
634
+
572
635
  end